RBAC
RBAC: 基于角色的权限管理
简单理解为:谁扮演什么角色, 被允许做什么操作
用户对象:user: 当前操作用户
角色对象:role:表示权限操作许可权的集合
权限对象:permission: 资源操作许可权
shiro的授权方式
Subject subject = SecurityUtils.getSubject();
if(subject.hasRole(“admin”)) {
//有权限
} else {
//无权限
}
通过在执行的Java方法上放置相应的注解完成
@RequiresRoles("admin")
@RequiresPermission(“employee:save”)
public void hello() {
//有权限
}
通过相应的标签完成
<shiro:hasRole name="admin">
<!— 有权限 —>
</shiro:hasRole>
权限表达式定义
在ini文件中用户、角色、权限的配置规则是:“用户名=密码,角色1,角色2...” “角色=权限1,权限2...”,首先根据用户名找角色,再根据角色找权限,角色是权限集合。
权限字符串的规则是:“资源标识符:操作:资源实例标识符”,意思是对哪个资源的哪个实例具有什么操作,“:”是资源/操作/实例的分割符,权限字符串也可以使用*通配符。
例子:
用户创建权限:user:create,或user:create:*
用户修改实例001的权限:user:update:001
用户实例001的所有权限:user:*:001
一般而已,我们操作只需要关注前面两节:
资源:操作 :
*:* : 所有资源的所有操作权限--->admin
使用ini方式来测试权限、角色
[users]
##用户zhangsan的密码是123,此用户具有role1和role2的角色
zhangsan=666,role1,role2
lisi=888,role2
[roles]
##角色role1对资源user拥有create、update权限
role1=user:create,user:update
#角色role2对资源user拥有create、delete权限
role2=user:create,user:delete
#角色role3对资源user拥有create权限
role3=user:create
public class TestShiro {
public static void main(String[] args) {
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-permission.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "666");
try {
subject.login(token);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("验证登录是否成功:"+subject.isAuthenticated());
System.out.println("测试角色开始");
System.out.println(subject.hasRole("role2"));
System.out.println(subject.hasAllRoles(Arrays.asList("role1","role2","role3")));
System.out.println(Arrays.toString(subject.hasRoles(Arrays.asList("role1","role2","role3"))));
subject.checkRole("role1");
try {
subject.checkRoles("role1","role2","role3");
} catch (AuthorizationException e1) {
e1.printStackTrace();
}
System.out.println("测试角色结束");
System.out.println("------------------------");
System.out.println("测试权限开始");
System.out.println(subject.isPermitted("user:delete"));
System.out.println(subject.isPermittedAll("user:delete","user:create"));
System.out.println(subject.isPermittedAll("user:delete","user:create","user:role"));
System.out.println(Arrays.toString(subject.isPermitted("user:delete","user:create","user:role")));
subject.checkPermission("user:delete");
try {
subject.checkPermission("user:role");
} catch (AuthorizationException e) {
}
System.out.println("测试权限结束");
subject.logout();
System.out.println("验证登录是否成功:"+subject.isAuthenticated());
}
}
通过自定义realm文件来模拟权限数据从数据库查询出来的
[main]
#声明一个realm
myReal = cn.com.zhangjh.shiro.PermissionRealm
#指定SecurityManager的realms实现
securityManager.realms=$myReal
public class PermissionRealm extends AuthorizingRealm{
@Override
public String getName() {
return "PermissionRealm";
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
String username = (String) principal.getPrimaryPrincipal();
List<String> roles = new ArrayList<>();
List<String> permission = new ArrayList<>();
roles.add("role3");
permission.add("user:delete");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRoles(roles);
info.addStringPermissions(permission);
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println(token);
String username = (String) token.getPrincipal();
if(!"zhangsan".equals(username)){
return null;
}
String password = "666";
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password, getName());
return info;
}
}
授权过程
1、首先调用Subject.isPermitted*/hasRole*接口,其会委托给SecurityManager,而SecurityManager接着会委托给Authorizer
2、Authorizer是真正的授权者,如果我们调用如isPermitted(“user:view”),其首先会通过PermissionResolver把字符串转换成相应的Permission实例;
3、在进行授权之前,其会调用相应的Realm获取Subject相应的角色/权限用于匹配传入的角色/权限;
4、Authorizer会判断Realm的角色/权限是否和传入的匹配,如果有多个Realm,会委托给ModularRealmAuthorizer进行循环判断,如果匹配如isPermitted*/hasRole*会返回true,否则返回false表示授权失败。