1.权限管理的概念
基本上涉及到用户参与的系统都要进行权限管理,权限管理属于系统安全的范畴,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户可以访问而且只能访问自己被授权的资源。权限管理包括用户身份认证和授权两部分,简称**认证授权**。对于需要访问控制的资源用户首先经过身份认证,认证通过后用户具有该资源的访问权限方可访问。
2.认证
1.认证的概念
-
认证:用户访问系统的控制
2.认证中抽象出的对象
-
subject :主体相当于之前的user,访问系统的用户,主体可以是用户、程序等,进行认证的都称为主体;
-
Principal:身份信息,是主体(subject)进行身份认证的标识,标识必须具有唯一性,如用户名、手机号、邮箱地址等,一个主体可以有多个身份,但是必须有一个主身份(Primary Principal)。
-
credential:凭证信息,是只有主体自己知道的安全信息,如密码、证书等.
3.授权
1.授权的概念
-
授权,即访问控制,控制谁能访问哪些资源。主体进行身份认证后需要分配权限方可访问系统的资源,对于某些资源没有权限是无法访问的。
2.授权中抽象对象
-
Who,即主体(Subject),主体需要访问系统中的资源。
-
What,即资源(Resource),如系统菜单、页面、按钮、类方法、系统商品信息等。资源包括资源类型和资源实例,比如商品信息为资源类型,类型为t01的商品为资源实例,编号为001的商品信息也属于资源实例。
-
How,权限/许可(Permission),规定了主体对资源的操作许可,权限离开资源没有意义,如用户查询权限、用户添加权限、某个类方法的调用权限、编号为001用户的修改权限等,通过权限可知主体对哪些资源都有哪些操作许可。权限分为粗颗粒和细颗粒,粗颗粒权限是指对资源类型的权限,细颗粒权限是对资源实例的权限。
4.权限模型
主体(账号、密码)
资源(资源名称、访问地址)
权限(权限名称、资源id)
角色(角色名称)
角色和权限关系(角色id、权限id)
主体和角色关系(主体id、角色id)
通常企业开发中将资源和权限表合并为一张权限表,如下:
资源(资源名称、访问地址)
权限(权限名称、资源id)
合并为:
权限(权限名称、资源名称、资源访问地址)
上图常被称为权限管理的通用模型,不过企业在开发中根据系统自身的特点还会对上图进行修改,但是用户、角色、权限、用户角色关系、角色权限关系是需要去理解的。
5.权限控制的方案
1.基于角色的权限控制
if(主体.hasRole("总经理角色id")){
查询工资
}
2.基于资源的权限控制
RBAC基于资源的访问控制(Resource-Based Access Control)是以资源为中心进行访问控制,比如:主体必须具有查询工资权限才可以查询员工工资信息等,访问控制流程如下:
if(主体.hasRole("查询工资的权限")){
查询工资
}
6.什么是shiro
Shiro是apache旗下一个开源框架,它将软件系统的安全认证相关的功能抽取出来,实现用户身份认证,权限授权、加密、会话管理等功能,组成了一个通用的安全认证框架.
7.为什么要学shiro
既然shiro将安全认证相关的功能抽取出来组成一个框架,使用shiro就可以非常快速的完成认证、授权等功能的开发,降低系统成本。shiro使用广泛,shiro可以运行在web应用,非web应用,集群分布式应用中越来越多的用户开始使用shiro。java领域中spring security(原名Acegi)也是一个开源的权限管理框架,但是spring security依赖spring运行,而shiro就相对独立,最主要是因为shiro使用简单、灵活,所以现在越来越多的用户选择shiro。
8.shiro的核心架构图
9.shiro的第一个程序
1.导入jar
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.3.2</version>
</dependency>
2.第一个认证的程序
//获取安全管理器工厂
IniSecurityManagerFactory iniSecurityManagerFactory=new IniSecurityManagerFactory("classpath:shiro.ini");
//获取安全管理器
SecurityManager securityManager=iniSecurityManagerFactory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
//获取主体对象
Subject subject = SecurityUtils.getSubject();
//token就是用户的令牌 包含用户的身份信息和凭证信息
AuthenticationToken token=new UsernamePasswordToken("zhangsan","1234567");
try {
subject.login(token);
} catch (AuthenticationException e) {
e.printStackTrace();
}
boolean authenticated = subject.isAuthenticated();
3.配置文件
[users]
zhangsan=123456
lisi=123456
注意:shiro中主体是否认证成功是通过抛异常的形式体现的,一般会抛出两个异常
-
UnknownAccountException 账号异常
-
IncorrectCredentialsException 密码异常
10.shiro认证连接数据库
1.源码追踪中出现的关键对象
AuthenticatingRealm //抽象类
//3.关键属性 该属性为凭证匹配器
CredentialsMatcher credentialsMatcher;
//1.该方法为抽象方法 其作用使用来获取数据
protected abstract AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken var1) throws AuthenticationException;
SimpleAccountRealm
//2.实现了AuthenticatingRealm抽象方法,用来获取配置文件中的用户信息,该类不做数据比对
SimpleCredentialsMatcher
//4.shiro中默认的凭证匹配器
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
Object tokenCredentials = this.getCredentials(token);
Object accountCredentials = this.getCredentials(info);
return this.equals(tokenCredentials, accountCredentials);
}
2.连接数据库
1.开发自定义realm
public class MyRealm extends AuthenticatingRealm {
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//略 数据操作 并且根据相应格式返回 不做比对
}
}
2.告知shiro要使用自定义realm
[main]
#自定义 realm
customRealm=com.lhc.day1.MyRealm
#将realm设置到securityManager
securityManager.realms=$customRealm
注意:需要导入一个jar
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
11.shiro的加密认证方式
1.realm返回密文数据
public class MyRealm extends AuthenticatingRealm {
2.修改配置文件,加入凭证匹配器的相关配置
[main]
#自定义凭证匹配器
hashedCredentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#自定义 realm
customRealm=com.lhc.day1.MyRealm
#凭证匹配器告诉谁
customRealm.credentialsMatcher=$hashedCredentialsMatcher
hashedCredentialsMatcher.hashAlgorithmName=MD5
hashedCredentialsMatcher.hashIterations=1024
#将realm设置到securityManager
securityManager.realms=$customRealm
12.授权
1.授权数据来源于数据库
public class MyRealm extends AuthorizingRealm {
//获取数据 获取认证的数据
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token){
//数据库操作 基于身份信息查主体
}
//获取数据 获取授权的数据
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection var1){
//数据库操作 基于身份信息查主体 基于主体查角色 基于角色查权限
}
}
2.java环境下授权的api
-
基于角色
//判断当前主体是否包含此角色
boolean b = subject.hasRole("super");
List<String> list = Arrays.asList("super", "admin");
//判断当前主体是否包含某个角色
boolean[] booleans = subject.hasRoles(list);
//判断当前主体是否包含全部的角色
boolean b = subject.hasAllRoles(list); -
基于资源
boolean b = subject.isPermitted("admin:delete");
String[] strs={"admin:delete", "admin:add"};
boolean[] permitted = subject.isPermitted(strs);
boolean permittedAll = subject.isPermittedAll(strs);
3.权限的标识符
权限字符串的规则是:“资源标识符:操作:资源实例标识符”,意思是对哪个资源的哪个实例具有什么操作,“:”是资源/操作/实例的分割符,权限字符串也可以使用*通配符。
例子:
-
用户创建权限:user:create,或user:create:*
-
用户修改实例001的权限:user:update:001
-
用户实例001的所有权限:user:*:001
13.springboot环境下的认证和授权
1.相关的jar
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
2.配置shrio的核心过滤器
3.shiro中相关的标签
先导入标签库
<%