一、登录认证
(1)原理
使用FormAuthenticationFilter过虑器实现
将用户没有认证时,请求loginurl进行认证,用户身份和用户密码提交数据到loginurl,FormAuthenticationFilter拦截住取出request中的username和password(两个参数名称是可以配置的),FormAuthenticationFilter调用realm传入一个token(username和password),realm认证时根据username查询用户信息。如果查询不到,realm返回null,FormAuthenticationFilter向request域中填充一个参数(记录了异常信息)。
(2)登录代码实现
注意:将applicationContext.xml中Shiro的配置信息移到applicationContext-shiro.xml中
修改web.xml中spring的配置,新建applicationContext-shiro.xml文件,复制粘贴shiro过滤器bean.
在applicationContext-shiro.xml中配置登录提交路径:
登录代码实现:LoginController
@Controller public class LoginController { /** * 登陆提交地址,和applicationContext-shiro.xml中配置的loginurl一致 * * @return */ @RequestMapping("/login") public String login(HttpServletRequest request) throws Exception { // 如果登陆失败从request中获取认证异常信息,shiroLoginFailure就是shiro异常类的全限定名 String exceptionClassName = (String) request.getAttribute("shiroLoginFailure"); // 根据shiro返回的异常类路径判断,抛出指定异常信息 if (exceptionClassName != null) { if (UnknownAccountException.class.getName().equals(exceptionClassName)) { // 最终会抛给异常处理器 throw new Exception("账号不存在"); } else if (IncorrectCredentialsException.class.getName().equals(exceptionClassName)) { throw new Exception("用户名/密码错误"); } else { throw new Exception("未知错误");// 最终在异常处理器生成未知错误 } } // 此方法不处理登陆成功(认证成功),shiro认证成功会自动跳转到上一个请求路径 // 登陆失败还到login页面 return "login"; } }
(3) 配置登录认证拦截器
在applicationContext-shiro.xml中配置,使需要登录的url经过认证拦截器(这里配置为全部url)
(4)修改Realm的doGetAuthenticationInfo方法
@Autowired private sysUserMapper sysUserMapper; /** * 用于认证 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // token是用户输入的用户名和密码 // 第一步从token中取出用户名 String userName = (String) token.getPrincipal(); // 第二步:根据用户输入的userName从数据库查询 sysUser sysUser = null; sysUser = sysUserMapper.selectByUserName(userName); // 如果查询不到返回null if (sysUser == null) { return null; } // 从数据库查询到密码 String password = sysUser.getPassword(); // 盐 String salt = sysUser.getSalt(); // 如果查询到返回认证信息AuthenticationInfo // 将sysUser设置simpleAuthenticationInfo SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(sysUser, password, ByteSource.Util.bytes(salt), this.getName()); return simpleAuthenticationInfo; }
(5)设置凭证匹配器
数据库中存储到的md5的散列值,在realm中需要设置数据库中的散列值它使用散列算法及散列次数,让shiro进行散列对比时和原始数据库中的散列值使用的算法一致。
<!-- 自定义 realm --> <bean id="MyRealm" class="com.shiro.realm.MyRealm"> <!-- 将凭证匹配器设置到realm中,realm按照凭证匹配器的要求进行散列 --> <property name="credentialsMatcher" ref="credentialsMatcher"></property> </bean> <!-- 凭证匹配器 --> <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> <property name="hashAlgorithmName" value="md5"></property> <property name="hashIterations" value="1024"></property> </bean>
(6)登录页面
由于FormAuthenticationFilter的用户身份和密码的input的默认值(username和password),修改页面的账号和密码 的input的名称为username和password
(7)其他
取出shiro认证的用户信息
二、登出
不用我们去实现退出,只要去访问一个退出的url(该 url是可以不存在),由LogoutFilter拦截住,清除session。
在applicationContext-shiro.xml配置LogoutFilter:
三、授权
(1)使用PermissionsAuthorizationFilter
- 在applicationContext-shiro.xml中配置filter规则<!--商品查询需要商品查询权限 -->/items/queryItems.action = perms[item:query]。或者使用注解或者使用标签配置授权规则。
- 用户在认证通过后,请求/items/queryItems.action
- PermissionsAuthorizationFilter拦截,发现需要“item:query”权限
- PermissionsAuthorizationFilter调用realm中的doGetAuthorizationInfo获取数据库中正确的权限
- PermissionsAuthorizationFilter对item:query 和从realm中获取权限进行对比,如果“item:query”在realm返回的权限列表中,授权通过。
(2)修改Realm中doGetAuthorizationInfo方法
@Autowired private sysPermissionMapper sysPermissionMapper; /** * 用于授权 */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { // 从principals获取身份信息 // 将getPrimaryPrincipal方法返回的值转为真实的身份类型 // (在上面doGetAuthenticationInfo认证通过填充到SimpleAuthenticationInfo中) sysUser sysUser = (sysUser) principals.getPrimaryPrincipal(); // 根据身份信息获取权限信息 // 从数据库获取到权限数据 List<sysPermission> permissionList = null; try { permissionList = sysPermissionMapper.findSysPermissionList(sysUser.getId()); } catch (Exception e) { e.printStackTrace(); } // 单独定一个集合对象 List<String> permissions = new ArrayList<String>(); if (permissionList != null) { for (sysPermission sysPermission : permissionList) { // 将数据库中的权限标签 符放入集合 permissions.add(sysPermission.getPercode()); } } // 查到权限数据,返回授权信息(包括permissions信息) SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); simpleAuthorizationInfo.addStringPermissions(permissions); return simpleAuthorizationInfo; }
(3)在applicationContext-shiro.xml中配置filter规则
(4)使用注解进行权限控制
对controller开启AOP
在springmvc.xml中配置:
可能需要添加springmvc.xml的dtd支持
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd ">
在controller方法上配置权限规则
(5)jsp标签 授权
Jsp页面添加:
<%@tagliburi="http://shiro.apache.org/tags" prefix="shiro"%>页面示例