创建自定义MyRealm
类
有关Shiro的基础知识我这里就不过多介绍了,直接来干货,到最后会整合Spring来进行权限验证。
首先在使用Shiro的时候我们要考虑在什么样的环境下使用:
基本上我们也就这三个需求,所以同时我们也需要三个方法:
findUserByUserName(String username)
根据username查询用户,之后Shiro会根据查询出来的User的密码来和提交上来的密码进行比对。
findRoles(String username)
根据username查询该用户的所有角色,用于角色验证。
findPermissions(String username)
根据username查询他所拥有的权限信息,用于权限判断。
下面我贴一下我的mapper代码(PS:该项目依然是基于之前的SSM,不太清楚整合的请看SSM一)。
id, username, password,roleId select from t_user where userName=#{userName} select r.roleName from t_user u,t_role r where u.roleId=r.id and u.userName=#{userName} select p.permissionName from t_user u,t_role r,t_permission p where u.roleId=r.id and p.roleId=r.id and u.userName=#{userName}
很简单只有三个方法,分别对应上面所说的三个方法。对sql
稍微熟悉点的童鞋应该都能看懂,不太清楚就拷到数据库中执行一下就行了,数据库的Sql
也在我的github
上。实体类就比较简单了,就只有四个字段以及get,set方法。我就这里就不贴了,具体可以去github
上fork
我的源码。
现在就需要创建自定义的MyRealm
类,这个还是比较重要的。继承至Shiro
的AuthorizingRealm
类,用于处理自己的验证逻辑,下面贴一下我的代码:
package com.crossoverJie.shiro; import com.crossoverJie.pojo.T_user; import com.crossoverJie.service.T_userService; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import javax.annotation.Resource; import java.util.Set; /** * Created with IDEA * Created by ${jie.chen} on 2016/7/14. * Shiro自定义域 */ public class MyRealm extends AuthorizingRealm { @Resource private T_userService t_userService; /** * 用于的权限的认证。 * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { String username = principalCollection.getPrimaryPrincipal().toString() ; SimpleAuthorizationInfo info = new SimpleAuthorizationInfo() ; Set roleName = t_userService.findRoles(username) ; Set permissions = t_userService.findPermissions(username) ; info.setRoles(roleName); info.setStringPermissions(permissions); return info; } /** * 首先执行这个登录验证 * @param token * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { //获取用户账号 String username = token.getPrincipal().toString() ; T_user user = t_userService.findUserByUsername(username) ; if (user != null){ //将查询到的用户账号和密码存放到 authenticationInfo用于后面的权限判断。第三个参数传入realName。 AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUserName(),user.getPassword(), "a") ; return authenticationInfo ; }else{ return null ; } } }
继承AuthorizingRealm
类之后就需要覆写它的两个方法,doGetAuthorizationInfo
,doGetAuthenticationInfo
,这两个方法的作用我都有写注释,逻辑也比较简单。
doGetAuthenticationInfo
是用于登录验证的,在登录的时候需要将数据封装到Shiro
的一个token
中,执行shiro的login()
方法,之后只要我们将MyRealm
这个类配置到Spring中,登录的时候Shiro
就会自动的调用doGetAuthenticationInfo()
方法进行验证。
哦对了,忘了贴下登录的Controller
了:
package com.crossoverJie.controller; import com.crossoverJie.pojo.T_user; import com.crossoverJie.service.T_userService; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import javax.annotation.Resource; /** * Created with IDEA * Created by ${jie.chen} on 2016/7/14. * 后台Controller */ @Controller @RequestMapping("/") public class T_userController { @Resource private T_userService t_userService ; @RequestMapping("/loginAdmin") public String login(T_user user, Model model){ Subject subject = SecurityUtils.getSubject() ; UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(),user.getPassword()) ; try { subject.login(token); return "admin" ; }catch (Exception e){ //这里将异常打印关闭是因为如果登录失败的话会自动抛异常 // e.printStackTrace(); model.addAttribute("error","用户名或密码错误") ; return "../../login" ; } } @RequestMapping("/admin") public String admin(){ return "admin"; } @RequestMapping("/student") public String student(){ return "admin" ; } @RequestMapping("/teacher") public String teacher(){ return "admin" ; } }
主要就是login()
方法。逻辑比较简单,只是登录验证的时候不是像之前那样直接查询数据库然后返回是否有用户了,而是调用subject
的login()
方法,就是我上面提到的,调用login()
方法时Shiro
会自动调用我们自定义的MyRealm
类中的doGetAuthenticationInfo()
方法进行验证的,验证逻辑是先根据用户名查询用户,如果查询到的话再将查询到的用户名和密码放到SimpleAuthenticationInfo
对象中,Shiro会自动根据用户输入的密码和查询到的密码进行匹配,如果匹配不上就会抛出异常,匹配上之后就会执行doGetAuthorizationInfo()
进行相应的权限验证。
doGetAuthorizationInfo()
方法的处理逻辑也比较简单,根据用户名获取到他所拥有的角色以及权限,然后赋值到SimpleAuthorizationInfo
对象中即可,Shiro就会按照我们配置的XX角色对应XX权限来进行判断,这个配置在下面的整合中会讲到。
整合Spring
接下来应该是大家比较关系的一步:整合Spring
。
我是在之前的Spring SpringMVC Mybatis
的基础上进行整合的。