Shiro中的授权
授权
授权,即访问控制,控制谁能访问哪些资源。主体进行身份认证感需要分配权限方可访问系统的资源,对于某些资源没有权限是无法访问的关键对象。
关键对象
授权可简单理解为who对what(which)进行How操作:
Who,**即主体(Subject)**,主体需要访问系统中的资源。
What,**即资源(Resource)**,如系统菜单、页面、按钮、类方法、系统商品信息等。资源包括资源类型和资源实例,比如商品信息为资源类型,类型为t01的商品为资源实例,编号为001的商品信息也属于资源实例。
How,**权限/许可(Permission)**,规定了主体对资源的操作许可,权限离开资源没有意义,如用户查询权限、用户添加权限、某个类方法的调用权限、编号为001用户的修改权限等,通过权限可知主体对哪些资源都有哪些操作许可。
授权方式
基于角色的访问控制:
- RBAC基于角色的访问控制(Role-Based Access Control)是以角色为中心进行访问控制
if(subject.hasRole("admin")){
//操作什么资源
}
·基于资源的访问控制:
- RBAC基于资源的访问控制(Resource-Based Access Control)是以资源为中心进行访问控制
if(subject.isPermisson("user:*:find"))
{
//对所有用户具有查询权限
}
if(subject.isPermisson("user:update:01"))
{
//对01用户进行修改
}
权限字符串
权限字符串的规则是:资源标识符:操作:资源实例标识符,意思是对哪个资源的哪个实例具有什么操作,“:”是资源/操作/实例的分割符,权限字符串也可以使用*通配符。
例子:
- 用户创建权限:user:create,或user:create:*
- 用户修改实例001的权限:user:update:001
- 用户实例001的所有权限:user:*:001
Shiro中授权编程实现方式
1.编程式
Subject subject=SecurityUtils.getSubject();
if(subject.hashRole("admin")){
//有权限
}else{
//无权限
}
2.注解式
@RequiresRoles("admin")
public void hello(){
//有权限
}
3.标签式
JSP/GSP标签:在JSP/GSP页面通过相应的标签完成
<shiro:hasRole name="admin">
<!-有权限->
</shiro:hasRole>
注意:Thymeleaf中使用shiro需要额外的集成!
授权Demo
1.realm的实现
package org.syc.realm;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
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 org.apache.shiro.util.ByteSource;
/**
* 自定义realm,加盐处理
* 加入 md5+salt+hash散列
*/
public class CustomerMd5Realm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("进入授权方法++++++++++++++++++++");
//可以根据身份信息principalCollection获取当前用户的角色信息(从数据库),以及权限信息
//假设xiaochen 有两个角色 管理员admin 用户user
/* String primaryPrincipal = (String)principalCollection.getPrimaryPrincipal();
System.out.println("身份信息:"+primaryPrincipal);*/
SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo();
//将数据库中查询的角色信息赋值给权限对象,以下使用假数据
simpleAuthorizationInfo.addRole("admin");
simpleAuthorizationInfo.addRole("user");
//将数据库中查询的权限信息赋值给权限对象
//以下使用假数据"user:*:01" 即:当前用户对01实例具有一切操作权限
//"product:create" 对product具有创建权限
simpleAuthorizationInfo.addStringPermission("user:*:01");
simpleAuthorizationInfo.addStringPermission("product:create");
return simpleAuthorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取身份信息
String principal=(String) token.getPrincipal();
if("xiaochen".equals(principal)){
//参数1:返回数据库中正确的用户名;
//参数2:返回数据库中的正确md5+salt处理后的密码(可根据用户名principal在数据库中查出,
//下面先使用假数据 :"123"经过md5+salt+hash处理后得到的32位字符串,其中sale为"X^^#DD",散列次数为1024);
//参数3:注册时处理密码的随机盐
//参数4:提供当前realm的名字,this.getName();
SimpleAuthenticationInfo info= new SimpleAuthenticationInfo
(principal,
"cf4eb5b9c210015849a5da931f0a3f37",
ByteSource.Util.bytes("X^^#DD"),
this.getName());
return info;
}
return null;
}
}
2.测试类:
package org.syc;
import com.sun.org.apache.bcel.internal.generic.FSUB;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;
import org.syc.realm.CustomerMd5Realm;
import org.syc.realm.CustomerRealm;
import java.util.ArrayList;
import java.util.List;
public class TestCustomerMD5RealmAuthenticator {
public static void main(String[] args) {
//创建securityManager
DefaultSecurityManager defaultSecurityManager=new DefaultSecurityManager();
//设置自定义realm
CustomerMd5Realm realm=new CustomerMd5Realm();
/**
* 修改shiro的默认密码校验策略
* 设置realm使用hash凭证匹配器
*/
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
credentialsMatcher.setHashAlgorithmName("md5");//设置凭证匹配器的匹配策略,采用的算法
credentialsMatcher.setHashIterations(1024);//散列次数
realm.setCredentialsMatcher(credentialsMatcher);
defaultSecurityManager.setRealm(realm);
//给安全工具类设置将安全管理器
SecurityUtils.setSecurityManager(defaultSecurityManager);
//通过安全工具类获取subject
Subject subject=SecurityUtils.getSubject();
//创建token
UsernamePasswordToken token=new UsernamePasswordToken("xiaochen","123");
//认证
try {
subject.login(token);
System.out.println("登录成功了");
System.out.println(subject.isAuthenticated());
}
catch (UnknownAccountException e){
e.printStackTrace();
System.out.println("认证失败:用户名不存在");
}
catch ( IncorrectCredentialsException e){
e.printStackTrace();
System.out.println("认证失败:密码错误");
}
// 认证用户的授权
// 1.基于单角色的授权
if(subject.isAuthenticated()){
System.out.println("是否具有管理员角色:"+subject.hasRole("admin"));
System.out.println("是否具有用户角色:"+subject.hasRole("user"));
//2.基于多角色的授权
ArrayList list=new ArrayList();
list.add("user");
list.add("admin");
System.out.println("是否同时具有管理员和用户两个角色:"+ subject.hasAllRoles(list));
//3.基于是否具有其中一个角色的授权
boolean[] booleans=subject.hasRoles(Arrays.asList("user","admin","super"));
for (boolean b:booleans
) {
System.out.println("是否具有管理员和用户和超级管理员其中的一个角色:"+ b);
}System.out.println("================================================================================");
//4.基于权限字符串的访问控制 → 资源访问符:操作:资源类型
System.out.println("当前用户是否具有对01的更新权限:"+subject.isPermitted("user:update:01"));
System.out.println("当前用户是否具有product创建权限:"+subject.isPermitted("product:create"));
System.out.println("当前用户是否同时具有对01的更新权限和product创建权限:"+subject.isPermittedAll("user:update:01","product:create"));
}
}
}
3.运行结果:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
登录成功了
true
进入授权方法++++++++++++++++++++
是否具有管理员角色:true
进入授权方法++++++++++++++++++++
是否具有用户角色:true
进入授权方法++++++++++++++++++++
进入授权方法++++++++++++++++++++
是否同时具有管理员和用户两个角色:true
进入授权方法++++++++++++++++++++
进入授权方法++++++++++++++++++++
进入授权方法++++++++++++++++++++
是否具有管理员和用户和超级管理员其中的一个角色:true
是否具有管理员和用户和超级管理员其中的一个角色:true
是否具有管理员和用户和超级管理员其中的一个角色:false
================================================================================
进入授权方法++++++++++++++++++++
当前用户是否具有对01的更新权限:true
进入授权方法++++++++++++++++++++
当前用户是否具有product创建权限:true
进入授权方法++++++++++++++++++++
进入授权方法++++++++++++++++++++
当前用户是否同时具有对01的更新权限和product创建权限:true
Process finished with exit code 0
给个饭钱?
- Post link: http://sovzn.github.io/2020/12/31/Shiro-%E6%8E%88%E6%9D%83/
- Copyright Notice: All articles in this blog are licensed under unless otherwise stated.
若没有本文 Issue,您可以使用 Comment 模版新建。
GitHub Issues