授权
授权概述
授权,也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作等)。在授权中需了解的几个关键对象:主体(Subject)、资源(Resource)、权限(Permission)、 角色(Role)。
关键对象介绍
主体:主体,即访问应用的用户,在Shiro中使用Subject代表该用户。用户只有授权后才允许访问相应的资源。
资源:在应用中用户可以访问的任何东西,比如访问JSP 页面、查看/编辑某些数据、访问某个业务方法、打印文本等等都是资源。用户只要授权后才能访问。
权限:安全策略中的原子授权单位,通过权限我们可以表示在应用中用户有没有操作某个资源的权力。即权限表示在应用中用户能不能访问某个资源,如:访问用户列表页面查看/新增/修改/删除用户数据(即很多时候都是CRUD式权限控制)打印文档等等。
角色:角色代表了操作集合,可以理解为权限的集合,一般情况下我们会赋予用户角色而不是权限,即这样用户可以拥有一组权限,赋予权限时比较方便。典型的如:项目经理、技术总监、CTO、开发工程师等都是角色,不同的角色拥有一组不同的权限。
授权流程
相关方法说明:
//判断是否有角色
subject.hasRole("");
//分别判断用户是否具有List中每个内容
subject.hashRoles(List);
//返回boolean,要求参数中所有角色用户都需要具有
subject.hasAllRoles(Collection);
//判断是否具有权限.
subject.isPermitted("");
shiro.ini方式实现授权
1、配置shiro.ini。
# 配置用户
[users]
zhangsan=123456,role1
lisi=123456,role3
# 配置角色
[roles]
role1=user:view,user:create,user:delete,user:update
role2=user:view
role3=user:view,user:create
权限标识符号规则:资源:操作:实例
,中间使用半角:分隔。
user:create:01
:表示对用户资源的01实例进行create操作。
user:create
:表示对用户资源进行create操作,相当于user:create:*
,对所有用户资源实例进行create操作。
user:*:01
:表示对用户资源实例01进行所有操作。
2、测试用户是否有当前角色和权限。
package com.coydone.test;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import java.util.ArrayList;
import java.util.List;
public class AuthUserTeat {
public static void main(String[] args) {
//1、接收用户名和密码
String username = "zhangsan";
String password = "123456";
//2、把用户名和密码封装
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
//3、创建安全管理器的工厂
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
//4、从Factory中得到安全管理器
SecurityManager securityManager = factory.getInstance();
//5、把securityManager和Subject绑定到当前线程
SecurityUtils.setSecurityManager(securityManager);
//6、从SecurityUtils中得到subject
Subject subject = SecurityUtils.getSubject();
//7、去认证
try {
subject.login(token);
System.out.println("认证通过");
} catch (AuthenticationException e) {
System.out.println("用户名或密码不正确");
}
/*
catch (IncorrectCredentialsException e) {
System.out.println("密码不正确");
} catch (UnknownAccountException e) {
System.out.println("用户名不存在");
}
*/
//8、查看认证状态
System.out.println("认证状态:"+subject.isAuthenticated());
//查看用户是否有role1的角色
System.out.println("用户是否有role1的角色:"+subject.hasRole("role1"));
//查看用户是否有role1、role2的角色
List<String> list = new ArrayList<>();
list.add("role1");
list.add("role2");
boolean[] isRoles = subject.hasRoles(list);
for (boolean isRole: isRoles) {
System.out.println(isRole);
}
//查看用户是否有user:view的权限
System.out.println(subject.isPermitted("user:view"));
//9、退出
subject.logout();
System.out.println("认证状态:"+subject.isAuthenticated());
}
}
注意,从以上的代码中可以看出我们的用户,密码,角色,权限都是在shrio.ini里面配置的,但是实际开发中我们的所有数据都是从数据库里面来的,如何实现呢,那就要使用数据和+自定义realm。
自定义Realm实现授权
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
//创建授权对象
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
//添加角色
info.addRole("role1");
info.addRole("role2");
//添加权限
info.addStringPermission("user:view");
info.addStringPermission("user:create");
info.addStringPermission("user:delete");
info.addStringPermission("user:update");
return info;
}
总结
Realm中有两个方法:doGetAuthenticationInfo()
用作认证,doGetAuthorizationInfo()用作授权
。
当hasRoles()、hasRole()、isPermised()、isPermisedAll()方法被调用时,doGetAuthorizationInfo()
方法就被执行一次。所以在开发中去查询用户权限的代码应该写在认证里面,因为认证只会执行一次。在授权中可以用principals.getPrimaryPrincipal()
方法获取认证中的SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password,this.getName());
中的第一个参数。这个参数可以是任意类型。
所以一般在认证方法里面查询用户权限和角色之后使用一个ActiveUser类把用户、角色、权限封装传递给授权的方法。
评论区