Shiro简单授权原理分析

深藏阁楼爱情的钟 2022-08-07 03:41 272阅读 0赞

Shiro授权简介

Shiro授权简单来说分为两种类型:

  1. 粗粒度的:也就是代码中直接写入和角色的绑定。
  2. 细粒度的:代码中写入的是和权限的绑定,而角色到权限和可配置的。

对于粗粒度来说,若角色对应权限有改变的话,那么则需要更改代码,很不方便。而细粒度的好处显而易见,所以一般项目中应该都采用细粒度的权限配置。

源码及流程分析

那么Shiro中是如何来完成权限检验的呢?
通过调用Subject.hasRoles(...)Subject.isPermitted(...)
另外还有Subject.checkRoles(...)Subject.checkPermissions(...)
前两种和后两种的区别是,后两种在没有权限时会抛出异常。

关于角色,相信你都会定义,因为就是一个名字,比如admin、vip、user等。
而对于权限的定义,就需要有一套规则了。在Shiro中我们可以这么来定义权限字符串:资源标识符:操作:对象实例ID。另外这里支持通配符配置,
比如:
user:create表示对usercreate的权限(这里省略了:对象实例ID,等价于user:create:*
user:*表示对user拥有所有操作的权限(create,update,delete,view)
user:view:1表示对user的1实例有view的权限
差不多就类似这样,就不多说了。Shiro内部会有一个PermissionResolver来负责将这类字符串解析为Permission对象。

下面分析一下授权的流程:

  1. 当我们调用Subject.hasRole(...)
  2. 首先会委托给securityManager来处理,而securityManager内部有一个Authorizer来做真正的授权,默认实现为ModularRealmAuthorizer
  3. ModularRealmAuthorizer可以根据多个Realm来判断是否拥有相应的角色,其中只要某个Realm匹配,则返回true
  4. AuthorizingRealm对于判断hasRole的逻辑也很简单

    protected boolean hasRole(String roleIdentifier, AuthorizationInfo info) {

    1. return info != null && info.getRoles() != null && info.getRoles().contains(roleIdentifier);
    2. }

而对于Subject.isPermitted(...)稍微会显得复杂一些,前三步都一样,就是AuthorizingRealm对于判断isPermitted的逻辑稍微有点不一样。它会先将权限字符串转换成Permission,将用户的权限转换成List<Permission>,这里的List<Permission>由三个部分组成:

  • 通过AuthorizationInfo.getObjectPermissions()得到Permission实例集合
  • 通过AuthorizationInfo. getStringPermissions()得到字符串集合并通过PermissionResolver解析为Permission实例
  • 然后获取用户的角色,并通过RolePermissionResolver解析角色对应的权限集合(默认没有实现,可以自己提供)

JdbcRealm的实现是使用了stringPermissions,可能第一想法以为它是用了RolePermissionResolver吧。
好了,接下来,用PermissionList进行匹配,其中遍历用户权限的匹配方法就是implies(...),这个单词可以理解成“蕴含”的意思,这样就比较好理解了。

  1. private boolean isPermitted(Permission permission, AuthorizationInfo info) {
  2. Collection<Permission> perms = getPermissions(info);
  3. if (perms != null && !perms.isEmpty()) {
  4. for (Permission perm : perms) {
  5. if (perm.implies(permission)) {
  6. return true;
  7. }
  8. }
  9. }
  10. return false;
  11. }

举个例子,比如user:*权限impliesuser:create权限,这就是一种蕴含关系。

具体用法

一般有编程式和声明式两种:

  • 编程式:

    Subject subject = SecurityUtils.getSubject();
    if(subject.hasRole(“admin”)) {

    1. //有权限

    } else {

    1. //无权限

    }

  • 声明式:

    @RequiresRoles(“admin”)
    public void hello() {

    1. //有权限

    }

没有权限的话就抛出相应的异常。而我们只需要捕获异常做出相应的处理就可以了,在Spring中是可以配置一个全局的ExceptionHandler的。当然在Spring3.2之后的版本还提供了@ControllerAdvice来增强Controller,其中定义的所有@ExceptionHandler方法将会应用于所有的@RequestMapping方法,那么我们可以这么来定义异常处理类:

  1. @ControllerAdvice
  2. public class DefaultExceptionHandler {
  3. @ExceptionHandler( { UnauthorizedException.class })
  4. @ResponseStatus(HttpStatus.UNAUTHORIZED)
  5. public ModelAndView processUnauthorizedException(
  6. NativeWebRequest request, UnauthorizedException e) {
  7. ModelAndView mv = new ModelAndView();
  8. mv.addObject("contextPath", request.getContextPath());
  9. mv.addObject("exception", e);
  10. mv.setViewName("special/unauthorized");
  11. return mv;
  12. }
  13. }

当然对于编程式的也可以直接使用subject.checkRoles(“admin”),这样一来也会抛出异常并被ExceptionHandler捕获了。

这里若启用声明式的鉴权,还需要启用aspectJ自动代理,并支持对类的代理。

  1. <aop:aspectj-autoproxy proxy-target-class="true" />
  2. <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
  3. <property name="securityManager" ref="securityManager" />
  4. </bean>

下一篇文章会写一个Spring项目中整合JdbcRealm来实现鉴权的实例。

发表评论

表情:
评论列表 (有 0 条评论,272人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Shiro授权

    授权 • 授权,也叫**访问控制,即在应用中控制谁访问哪些资源**(如访问页面/编辑数据/页面操作 等)。在授权中需了解的几个关键对象:主体(Subject)、资源...

    相关 shiro授权

    意:在realm的情况下,其权限认证策略也是只要有一个realm的权限ok就好了,所以如果有多个realm的话,只要写其中一个就可以了。 来到我们写的realm: 将...

    相关 Shiro--授权

    首发网址:[Shiro--授权\_IT利刃出鞘的博客-CSDN博客][Shiro--_IT_-CSDN] 其他网址 [shiro简单配置\_运维\_都是浮云-CSDN博

    相关 Shiro---授权

    什么是授权? shiro是一款安全框架,开发中经常使用Shiro来进行认证和授权,所谓授权,即访问控制,控制谁能访问哪些资源。主体进行身份认证后需要分配权限方可访问系统的

    相关 Shiro--授权

    授权 授权,也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作等)。在授权中需了解的几个关键对象:主体(Subject)、资源(Resource