接上文
(题外话:好像hexo对Markdown里Java的渲染不是很好,注解会嵌到其他行去?)
编写Controller
做用户认证,首先得有一个Controller,生成一个User对象。由于研究对象是shiro,先不写实际页面,用一个简单的表单向Controller提交对象。
直接上Controller部分代码:
1 |
|
先实例化一个subject,校验后调用.login()方法,并传入包含用户名(可以是能用来登陆的其他东西)和密码。
之前在Spring配置中将Realm注入到SecurityManager,因此会跳转到Realm处理。
(出于业务需求的原因,本文暂时不涉及多个Realm的情况,可以参考http://blog.csdn.net/xiangwanpeng/article/details/54802509 )
编写Realm具体方法之认证
跳转之后,首先进入doGetAuthenticationInfo方法,示例代码如下:
1 |
|
这里使用了userMapper在数据库中取验证信息,当然也可以使用userService封装好的方法,随意发挥。
如果登陆失败,可以自己抛出并处理各种异常,shiro自带用户锁定、同IP尝试次数过多等非常丰富的异常。由于是小系统,不做复杂处理。
假如这个方法通过了,我们会return一个包含了用户名(确切讲是用户标识,根据业务场景不同而不同),密码(其他授权信息也可以)以及当前类名的authcInfo对象。
这个对象这里我们没有使用,但是可以用在JSP标签中,参考此文:http://www.sojson.com/blog/144.html
编写Realm具体方法之授权
如果上一个方法没有抛出异常,会进入doGetAuthorizationInfo方法,传入对象则是一个principalCollection。
1 | protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { |
这个方法的作用,是从数据源中,根据用户标识(邮箱),取出所对应的权限(无论是以字段形式存在于用户实体,或者是另起一张表,都只是形式,目的是要取出权限)。
并且以字符串的set形式,存入authzInfo对象中并且return,return的这个对象稍后可以在JSP中以tag形式调用。也可以直接在Spring配置中写上/admin = authz,使用shiro自带的Filter进行过滤。
至此,使用Shiro在SSM应用中的认证、授权已经完成。这里实现了最简单的功能,系统只有两个角色(用户、管理员),管理员能访问后台系统,用户不能访问,仅此而已。
事实上shiro的功能远远不止这些,多用户、多权限,甚至多数据源、多Realm都可以做到。甚至还提供了密码加盐存储的工具类,而这一切都能和Spring 完美整合。
使用shiro的目的,首先是无需手写Filter拦截每一个没有权限的请求,其次是不必手写代码去判断用户权限,不必手写代码实现每个权限能做的事,也不必手动处理登陆失败的情景,节省大量工作量。
题外话
在之前的学习过程中,我看到的demo为了实现全部功能,将用户、权限全部实现,起了五张表,分别存储用户、权限、角色,用户-角色关系,角色-权限关系。
更丧心病狂的是,权限表还有roleSign,roleName,roleDescription三个字段,而实际上放进authzInfo的只有roleSign一个字符串。
我尝试直接阅读代码,一个Realm三个Service三个实体,让我对功能一头雾水,今早突然醒悟,既然源码都开放了,我何必苦苦猜测功能,直接git clone 打breakpoint debug,模拟一次登录,终于豁然开朗。