本文核心:RBAC权限模型,Shiro与Spring的整合,Shiro认证与授权【集成到项目中】。
这系列博客是记录自己做过项目学到知识。one、two代表项目编号。
前言:
后台管理系统
技术选型:ssm + easyui + ajax + js/jq + jsp + mysql + redis
工具版本:jdk1.8 + tomcat7/8 + mysql8.0.11 + idea2017 + spring4.1.13
项目规范:maven3.3.9 + git
shiro认证与授权可以通过配置shiro.ini文件。这里采用Shrio与Spring项目集成的方式,将Shiro的配置文件配置到Spring配置文件中。
一:RBAC权限模型【管理系统权限】
首先介绍一下,什么是认证,什么是授权。
认证:
Subject:主体
访问系统的用户,主体可以是用户、程序等,进行认证的都称为主体。
Principal:身份信息
是主体(subject)进行身份认证的标识,标识必须具有唯一性,如用户名、手机号、邮箱地址等,一个主体可以有多个身份,但是必须有一个主身份(Primary Principal)。
credential:凭证信息
是只有主体自己知道的安全信息,如密码、证书等。
token(令牌):身份信息+凭证信息的组合=一个令牌
授权:
Who,即主体(Subject),主体需要访问系统中的资源。
What,即资源(Resource),如系统菜单、页面、按钮、类方法、系统商品信息等。资源包括资源类型和资源实例,比如商品信息为资源类型,类型为t01的商品为资源实例,编号为001的商品信息也属于资源实例。
How,权限/许可(Permission),规定了主体对资源的操作许可,权限离开资源没有意义,如用户查询权限、用户添加权限、某个类方法的调用权限、编号为001用户的修改权限等,通过权限可知主体对哪些资源都有哪些操作许可
RBAC认为权限的过程可以抽象概括为:判断【Who是否可以对What进行How的访问操作(Operator)】这个逻辑表达式的值是否为True的求解过程。
即将权限问题转换为Who、What、How的问题。who、what、how构成了访问权限三元组。
权限模型:
我们的数据库权限设计,需要五张表。这张图我已经详细解释了如何查询用户的角色和权限。【不补充数据库设计和Mapper文件的写法。】
二:Shiro与Spring整合
首先导入Shiro依赖和Shiro与Spring整合依赖 【默认已完成SSM项目框架搭建】
org.apache.shiro
shiro-core
1.3.1
org.apache.shiro
shiro-web
1.3.1
org.apache.shiro
shiro-spring
1.3.1
org.apache.shiro
shiro-ehcache
1.2.6
Web.xml配置 shiro的过滤器【Filter过滤器配置顺序即调用链传递的顺序,个人建议:如果配置SpringMVC自带的字符过滤器应放在Shiro过滤器前面。】
shiroFilter
org.springframework.web.filter.DelegatingFilterProxy
targetBeanName
shiroFilter
shiroFilter
/*
其中的
application-context-shiro.xml的配置文件
/Login_Jsp/login.jsp=anon
/Main_Jsp/main/main.jsp=authc
/**=anon
重点理解掌握 【过滤器的取值的含义】
过滤器:anon |不认证就可以访问资源 org.apache.shiro.web.filter.authc.AnonymousFilter
authc |表单认证 org.apache.shiro.web.filter.authc.FormAuthenticationFilter
user |用户认证成功或记住我 org.apache.shiro.web.filter.authc.UserFilter
logout|登出过滤器 org.apache.shiro.web.filter.authc.LogoutFilter
roles |角色授权过滤器 org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
perms |权限授权过滤器 org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
port |端口过滤器 org.apache.shiro.web.filter.authz.PortFilter
ssl |https过滤器 org.apache.shiro.web.filter.authz.SslFilter
rest |restful风格过滤器 org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
提示:我们将Shiro的配置单独为一个文件,因此需要将Shiro的配置文件导入Spring配置文件中。【代码省略】
三:自定义复杂的凭证匹配器
MyRealm 继承AuthorizingRealm 类,需要实现两个抽象方法。
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)//认证方法
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection)//授权方法
认证的过程:
①Controller接收参数用户名密码,web环境下获取主体,调用主体的Login方法。
@RequestMapping("/login")
public @ResponseBody String managerLogin(String managerName, String managerPwd, String enCode, HttpSession session){
//先判断验证码是否正确
String code=(String)session.getAttribute("code");
if(code.equalsIgnoreCase(enCode)) {
// 在web环境中安全管理器会自动进行初始化
// 获取主体
Subject subject = SecurityUtils.getSubject();
try {
subject.login(new UsernamePasswordToken(managerName,managerPwd));
session.setAttribute("managerName",managerName);
return "success";
} catch (Exception e) {
e.printStackTrace();
return "loser";
}
}else{
return "loser";
}
}
② 中间经过一系列的包装,方法走到doGetAuthenticationInfo【认证】,验证账号密码是否正确
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//首先强转为UsernamePasswordToken 可以获取到用户名->查询数据库->验证
UsernamePasswordToken token=(UsernamePasswordToken)authenticationToken;
String managerName=token.getUsername();
Manager manager=managerService.queryManagerByName(managerName);
if (manager!=null){
return new SimpleAuthenticationInfo(managerName,
manager.getManagerPwd(),
ByteSource.Util.bytes(manager.getManagerSalt()),
UUID.randomUUID().toString());
}
return null;
}
验证方法返回的SimpleAuthenticationInfo对象的四个参数: 用户名,加密后的密码,加密的盐,无重复的数。【采用哪种加密算法和散列运算的次数在配置文件中配置】 参考application-context-shiro.xml。
验证失败会以异常的形式抛出 【罗列常见的两种异常,我们可以捕获异常给予用户友好的提示。】
UnknownAccountException
账号不存在异常如下:
org.apache.shiro.authc.UnknownAccountException: No account found for user。。。。
IncorrectCredentialsException
当输入密码错误会抛此异常,如下:
org.apache.shiro.authc.IncorrectCredentialsException: Submitted credentials for token [org.apache.shiro.authc.UsernamePasswordToken - zhangsan, rememberMe=false] did not match the expected credentials.
授权的过程 【获取用户名->查询数据库->绑定角色、权限】
提示,只有先认证成功,才会走到授权这一步。
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取用户名 【登陆账号】
String username = (String) principalCollection.getPrimaryPrincipal();
List list=managerService.queryRole(username);
//这里只查询了角色
if(list!=null){
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
for (Role role : list) {
info.addRole(role.getRoleName());
}
return info;
}
return null;
}
在JSP页面我们一通过Shiro定义的标签轻松判断用户拥有哪些权限和角色,通过标签来控制页面的展示信息。
标签的使用和相关功能【18年7月14日 补充】
//JSP页面引入shiro标签库
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
//判断用户是否为游客
//判断用户是否已经登录(包括已认证和已记住)
//判断用户是否具有某个角色
//判断用户是否缺少某个角色
>//判断用户是否具有任意某个角色
//判断用户是否具有某个权限
//判断用户是否缺少某个权限