码迷,mamicode.com
首页 > 其他好文 > 详细

Shiro简单授权原理分析

时间:2015-03-03 13:36:41      阅读:17703      评论:0      收藏:0      [点我收藏+]

标签:授权   shiro   

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) {
        return info != null && info.getRoles() != null && info.getRoles().contains(roleIdentifier);
    }

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

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

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

   private boolean isPermitted(Permission permission, AuthorizationInfo info) {
        Collection<Permission> perms = getPermissions(info);
        if (perms != null && !perms.isEmpty()) {
            for (Permission perm : perms) {
                if (perm.implies(permission)) {
                    return true;
                }
            }
        }
        return false;
    }

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

具体用法

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

  • 编程式:
Subject subject = SecurityUtils.getSubject();
if(subject.hasRole(“admin”)) {
    //有权限
} else {
    //无权限
}
  • 声明式:
@RequiresRoles("admin")
public void hello() {
    //有权限
}

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

@ControllerAdvice
public class DefaultExceptionHandler {

    @ExceptionHandler( { UnauthorizedException.class })
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public ModelAndView processUnauthorizedException(
            NativeWebRequest request, UnauthorizedException e) {
        ModelAndView mv = new ModelAndView();
        mv.addObject("contextPath", request.getContextPath());
        mv.addObject("exception", e);
        mv.setViewName("special/unauthorized");
        return mv;
    }
}

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

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

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

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

Shiro简单授权原理分析

标签:授权   shiro   

原文地址:http://blog.csdn.net/u012345283/article/details/44034695

(3)
(7)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!