安全认证框架Shiro(三)- 源码角度解析shiro的权限验证
来源:互联网 发布:大数据的4v特性是指 编辑:程序博客网 时间:2024/05/22 04:11
安全认证框架Shiro(三)- 源码角度解析shiro的权限验证
- 安全认证框架Shiro三- 源码角度解析shiro的权限验证
- 第一前言
- 第二走下去
- shiro没配置权限验证的Url怎么处理
- 结论
第一:前言
承接上篇文章安全认证框架Shiro (二)- shiro过滤器工作原理
权限验证,一直是个难点,看起来是个很高大尚的概念,其实我理解的权限其实就是字符串,把它当成字符串,只要和用户对应的字符串匹配成功,则验证通过。验证权限可以理解为字符串匹配即可通过授权,url对应的权限是个字符串数组集合,所以同一个请求可能配置成多个权限,比如老板和总经理都可以查询员工的信息。访问该url需要一组权限集,只要能从realm里取到你拥有的权限,只要某个匹配即可授权通过。
第二:走下去
权限验证和身份验证前半部分流程一样直到走到PathMatchingFilter.onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue)这个方法都是一样的。
onPreHandler是处理权限验证的部分,不同的权限验证有一同的实现方式。
权限验证器包括如下:
其中较常用的是PermissionsAuthorizationFilter权限过滤器,如果自定义权限验证,一般继承自AuthorizationFilter。
前面流程这里不做介绍,不懂的可看安全认证框架Shiro (二)- shiro过滤器工作原理,
从AccessControlFilter.onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue)开始,不同类型过滤器不同逻辑。
参数mappedValue是对应的权限字符串。
如下图的“user:admin”:
我们先看看PermissionsAuthorizationFilter和FormAuthenticationFilter的appliedPaths数据有什么不同?如下
FormAuthenticationFilter.appliedPaths:
{ /login=null, /authenticated=null}
PermissionsAuthorizationFilter.appliedPaths:
{ /index.jsp=[Ljava.lang.String;@5a24afbf, /admin.jsp=[Ljava.lang.String;@54e35a8b}
其中权限里key对应的value值可参考如下:
解释:
key即是对应的需要处理的url,重点是value值,权限验证的value是有值的,非null,而value值即是权限字符串。
收到一个请求,先找到url对应的过滤器链,然后按序执行过滤器,同时mappedValue值也会一同传下去,通过realm查找用户对应的权限与mappedValue值比对,比对成功则继承下个过滤器验证。
讲那么多废话,下面上代码:
PermissionsAuthorizationFilter.isAccessAllowed():
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException { //取得subject Subject subject = getSubject(request, response); //取的访问该url需要的权限,比如:[user:admin],注意是字符串数组 String[] perms = (String[]) mappedValue; boolean isPermitted = true; if (perms != null && perms.length > 0) { if (perms.length == 1) { //单个权限验证, if (!subject.isPermitted(perms[0])) { isPermitted = false; } } else { //多个权限验证 if (!subject.isPermittedAll(perms)) { isPermitted = false; } } } return isPermitted; }
subject.isPermitted()方法先验证是否登陆过,没登陆过的用户根本没必要权限验证,直接失败返回false。若登陆过,通过securityManager.isPermitted(getPrincipals(), permission);执行从数据库或缓存查询用户权限操作,和permission比对(注意这时候permission还是类似“user:admin”的字符串),继续往下走直到AuthorizingRealm.isPermitted()方法:
public boolean isPermitted(PrincipalCollection principals, Permission permission) { //获得验证,角色等操作,即数据提供源 AuthorizationInfo info = getAuthorizationInfo(principals); return isPermitted(permission, info); }
调用getAuthorizationInfo()拿到AuthorizationInfo对象:
protected AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) { if (principals == null) { return null; } AuthorizationInfo info = null; if (log.isTraceEnabled()) { log.trace("Retrieving AuthorizationInfo for principals [" + principals + "]"); } Cache<Object, AuthorizationInfo> cache = getAvailableAuthorizationCache(); if (cache != null) { if (log.isTraceEnabled()) { log.trace("Attempting to retrieve the AuthorizationInfo from cache."); } Object key = getAuthorizationCacheKey(principals); info = cache.get(key); if (log.isTraceEnabled()) { if (info == null) { log.trace("No AuthorizationInfo found in cache for principals [" + principals + "]"); } else { log.trace("AuthorizationInfo found in cache for principals [" + principals + "]"); } } } if (info == null) { // Call template method if the info was not found in a cache info = doGetAuthorizationInfo(principals); // If the info is not null and the cache has been created, then cache the authorization info. if (info != null && cache != null) { if (log.isTraceEnabled()) { log.trace("Caching authorization info for principals: [" + principals + "]."); } Object key = getAuthorizationCacheKey(principals); cache.put(key, info); } } return info; }
getAuthorizationInfo先从缓存管理器里拿权限组,存在直接返回,如果没有则调用Realm实现子类的doGetAuthorizationInfo()方法,一般自定义的Reaml基本上都是继承AuthorizingRealm类,而且需要实现doGetAuthorizationInfo()方法,该方法从数据库查询数据组装到AuthorizationInfo子类对象里返回,且会保存到缓存里供下次调用。
查询出来的权限字符会和url需要的权限字符串比较,比较方法如下isPermitted():
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; }
如果匹配成功则有权限访问该url,否则无权限。
shiro没配置权限验证的Url怎么处理
在shiro里,如果没配置url过滤器,默认url在shiro里不会做任何验证的,会走spring过虑器。
看看AbstractShiroFilter.getExecutionChain()查询Url对应的过滤器链方法。默认是origChain,如果在过滤器管理器里找到再重新赋值,否则是默认值
protected FilterChain getExecutionChain(ServletRequest request, ServletResponse response, FilterChain origChain) { //默认过滤器,即ApplicationFilterChain FilterChain chain = origChain; FilterChainResolver resolver = getFilterChainResolver(); if (resolver == null) { log.debug("No FilterChainResolver configured. Returning original FilterChain."); return origChain; } FilterChain resolved = resolver.getChain(request, response, origChain); if (resolved != null) { log.trace("Resolved a configured FilterChain for the current request."); //不为null才赋值,否则取默认值 chain = resolved; } else { log.trace("No FilterChain configured for the current request. Using the default."); } return chain; }
结论
shiro在启动后,权限过滤器会维护一个类似
{ /index.jsp=[Ljava.lang.String;@5a24afbf, /admin.jsp=[Ljava.lang.String;@54e35a8b}
的集合,当接收到请求后,拿key对应的value值去与缓存或数据库里用户的权限对比。我们注意到,事先权限过滤器已经知道访问某个url对应哪个权限了,这是重点,慢慢品位。
未完待续….
- 安全认证框架Shiro(三)- 源码角度解析shiro的权限验证
- Shiro安全框架的登陆认证源码解析
- java安全框架-Shiro学习笔记(三)-权限认证
- shiro权限健康安全验证框架
- 基于权限安全框架Shiro的登录验证功能实现
- shiro权限验证框架
- shiro权限框架详解04-shiro认证
- Java权限验证框架Shiro的入门
- shiro框架权限验证逻辑
- Apache Shiro权限验证框架
- Shiro登录验证源码解析
- 安全认证框架Shiro (二)- shiro过滤器工作原理
- 【Shiro】Shiro从小白到大神(三)-权限认证(授权)
- 安全认证框架-Apache Shiro研究心得
- 安全认证框架-Apache Shiro研究心得
- 安全认证框架-Apache Shiro研究心得
- 安全认证框架-apache shiro研究心得
- AdminEAP框架-集成Shiro安全认证
- Android WebView加载Chromium动态库的过程分析
- HHUOJ_1003: 数字整除
- pullrefreshdemo
- 基于thinkPHP实现的微信自定义分享功能示例
- springMVC入门--1.新建springMVC工程
- 安全认证框架Shiro(三)- 源码角度解析shiro的权限验证
- IntelliJ IDEA 下的SVN使用
- eclipse发布项目之前编译步骤
- 如何获得select被选中option的值
- Java编程常用的快捷键
- 网络编程之网络基本概念复习思路
- ETL工具比较(Informatica ,SSIS,Kettle )
- lua 的 冒号和点的用法
- MATLAB画图符号标注