一、登录认证
(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"%>页面示例