前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Shiro技术架构之源码分析 原

Shiro技术架构之源码分析 原

作者头像
wuweixiang
发布2018-08-14 14:27:54
4160
发布2018-08-14 14:27:54
举报
文章被收录于专栏:吴伟祥吴伟祥

Shiro简介(技术选型时确定使用此框架)

主要四大模块

Ø 认证(进入系统前确认访问者身份,能否允许准入系统)

Ø 授权(判断用户是否有访问此资源的权限)

Ø 会话管理(主要是管理会话的生命周期,简单讲就是会话的增删改查)

Ø 加密(提供实现好的加密算法)

支持特性

WEB支持、缓存、并发、测试、模拟(run as)以及免密功能(remember me)。

记住: Shiro 不会去维护用户、维护权限;这些需要我们自己去设计/提供;然后通过

相应的接口注入给 Shiro 即可(把已有信息或信息渠道放入shiro内部,填补信息上空白,大体逻辑shiro已经帮我们完成,我们负责细节逻辑和信息)。

框架内关键概念、接口、类和流程(共两小节)

第一节:认证流程和授权流程;

第二节:概念的解释。

开始之前先简单介绍一下几个概念。

n 身份:principals (主体的标识,可以有多个,可以是任何东西,如用户名、邮箱等,唯一即可,但只有一个primary principal)。

n 证明/凭证:credentials(只有主体自己知道的信息,如密码/数字证书等)。

主要的相关接口和类:

Shiro内:

Ø Subject 主体,可以看做是与系统交互的那个“用户”(不一定是人)。

Ø SecurityManager 安全管理器,shiro里的指挥官。它管理着所有 Subject、且负责进行认证和授权、及会话、缓存的管理。

Ø Realm 域,数据源,SecurityManager的数据管家,验证用户信息,权限等都从realm中取。

Ø Authenticator  认证器,负责主体认证的,这是一个扩展点,如果用户觉得 Shiro 默认的不好,可以自定义实现;其需要认证策略(Authentication Strategy),即什么情况下算用户认证通过了。

Ø Authorizer 授权器,用来决定主体是否有权限进行相应的操作;即控制着用户能访问应用中的哪些功能;

Ø SessionManager 会话管理,Session需要有人去管理它的生命周期,这个组件就是 SessionManager;而 Shiro 并不仅仅可以用在 Web 环境,也可以用在如普通的 JavaSE 环境、EJB 等环境;所以Shiro 就抽象了一个自己的 Session来管理主体与应用之间交互的数据;这样的话,比如我们在 Web 环境用,刚开始是一台Web 服务器;接着又上了台 EJB 服务器;这时想把两台服务器的会话数据放到一个地方,这个时候就可以实现自己的分布式会话(如把数据放到 Redis服务器)

Ø SessionDAO 会话数据访问,主管数据的CRUD(增查改删),另外 SessionDAO中可以使用 Cache 进行缓存,以提高性能

Ø CacheManager 缓存控制器,如用户、角色、权限等的缓存。

Ø Cryptography 密码模块,Shiro 提供了一些常见的加密组件用于如密码加密/解密的。

下面开始讲解流程。

认证流程(验证访问系统用户的身份)

概念流:

代码流:

1初始化安全管理工厂Factory<SecurityManager>。

2初始化SecurityUtils,从工厂内获取SecurityManager,放入SecurityUtils内。

3从SecurityUtils内获取一个Subject,通过Subject.login(param:认证信息对象)方法完成认证操作。Subject其实现者是DelegatingSubject类,如果无异常认证成功。

细节:

以下流程中间细节可做了解,在最后我会给出总结和关键点。

Subject.login实际调用DelegatingSubject.login,紧接是securityManager.login

实际调用DefaultSecurityManager.login(),因为DefaultSecurityManager是securityManager接口的实现类。

紧接着调用认证方法authenticate(token),实际是调用AuthenticatingSecurityManager内的authenticate方法,紧接着交给authenticator.authenticate(token);

但实际调用的是AbstractAuthenticator的authenticate方法,接着方法内调用了doAuthenticate方法。

看到这里我们可以看到我们走到了doAuthenticate方法内。开始使用Realm来完成最后的认证。

这里shiro内采用的认证核心是AuthenticatingRealm(抽象类)来实现Realm接口,且在AuthenticatingRealm内getAuthenticationInfo是public final修饰的,所以其子类无法重写此方法。用户在自己设计realm的时候会继承AuthorizingRealm。而AuthorizingRealm是继承自AuthenticatingRealm所以这认证步骤就是shiro内部设计好的验证流程,用户改变不了这个步骤。现在我们进入到getAuthenticationInfo方法内。

因为这个getAuthenticationInfo不可被子类重写,那么我们就可以看到这个方法内不可被改变的两个重要步骤,doGetAuthenticationInfo(token)和assertCredentialsMatch(token,info),分别对应概念流里的“获取保留在系统内的认证信息”和“比对两者信息是否一致”。

第一步骤,doGetAuthenticationInfo这个步骤是根据用户输入的信息token,获取记录在系统内的用户信息info(有可能用户信息不存在,那时会有异常抛出或者返回值为null,具体由编码者自己实现)。

第二步骤,接下来执行到token和info的比较了。(token:用户输入的信息,info:根据token从系统内获取的用户信息)。具体的执行语句为assertCredentialsMatch(token, info),如上图红框内展示。也就是前面流转了那么多,最终做事情的是上图的两个红框内做的事情。获取用户存留在系统内的信息以及比对两者信息是否一致。现在我们进入assertCredentialsMatch方法内。

先看getCredentialsMatcher(),因为在AuthenticatingRealm内有一个私有域其类型就是CredentialsMatcher。但是CredentialsMatcher是一个接口,里面只有一个方法就是boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info)。参数是token和info,返回值为boolean类型。这个方法就是用来判断token和info实际是否匹配的地方,因为CredentialsMatcher是一个接口,我们必须自己实现这个接口来完成token和info的比对。至此整个认证流程就结束了。

总结,上文写了那么多那最终要完成的是什么呢?第一点,继承AuthorizingRealm,实现抽象方法内的doGetAuthenticationInfo,也就是我们要自己根据传入的token返回info,info是我们自己组好的,我们去哪拿信息呢?当然是持久层,具体就在我们自己写的realm内了。第二点,实现CredentialsMatcher(简称Matcher)接口,实现内里的方法,将我们自己提供的info信息和已有的token信息做比对,就是比对身份信息。写了那么多,其实就是那么简单的两个步骤,至此shiro的认证流程完毕。

鉴权流程(判断用户访问资源的权限)

授权即访问控制,它将判断用户在应用程序中对资源是否拥有相应的访问权限。 

三个核心元素:权限、角色和用户  

关于判断用户访问资源权限的问题,目前有两种常见的设计。

第一,基于角色的访问,就是一个用户只要有拥有这个角色那就可以访问这个资源。但是业务上不够灵活,一但业务经常变动则代码要经常改写发布,对于简单稳定的系统求快可以使用此种方案。

第二,基于资源权限的访问,这里也有角色的概念,但是角色是一组资源权限的集合,可以灵活赋予某个角色某个资源的操作权限,用户拥有角色就是拥有相应的一组资源权限的集合。业务变动的时候配置一下该角色的资源权限,或者新建角色赋予一组资源权限,不必再改写代码了。

无论是哪一种方式来处理用户的权限问题,但是概念上流程没有变动。

概念流:

代码流:

认证流程分析的很多,那么应该对shiro有一定了解了,鉴权流程的代码流这里就快速过掉了。

鉴权的时候,入口在Subject.isPermitted方法处调用顺序如下:

Subject.isPermitted

DelegatingSubject.isPermitted

AuthorizingSecurityManager.isPermitted

AuthorizingRealm.isPermitted

AuthorizingRealm.getAuthorizationInfo

protected abstract AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals);

关于资源的权限验证,shiro也是帮我们完成了,当然你觉得效率低可以重写。网上的教程很多我就不在这长篇累牍了。

总结,看了一下代码流程,要我们做些什么呢?如果想快速开发,没有特别要求。只有一点,继承AuthorizingRealm,实现抽象方法内的doGetAuthorizationInfo。主要的任务是根据传来的principalCollection,获取用户的角色集合和角色对应的所有资源权限。从哪里获取?在你自己定义的realm内从持久层获取。其余的部分就是shiro帮你完成,就是判断用户访问的这个资源在不在用户的权限集合内。至此授权流程完毕。

资源权限配置方式:

了解即可,一般为了效率不使用‘*’。

“user:view”等价于“user:view:*”;

“organization”等价于“organization:*”或者“organization:*:*”。

另外如“user:*”可以匹配如“user:delete”、“user:delete”可以匹配如“user:delete:1”、“user:*:1”可以匹配如“user:view:1”、“user”可以匹配“user:view”或“user:view:1”等。即*可以匹配所有,不加*可以进行前缀匹配;可以这么理解,这种方式实现了前缀匹配。

但是如“*:view”不能匹配“system:user:view”,需要使用“*:*:view”,即后缀匹配必须指定前缀(多个冒号就需要多个*来匹配)。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017/11/15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Shiro简介(技术选型时确定使用此框架)
    • 主要四大模块
      • 支持特性
        • 框架内关键概念、接口、类和流程(共两小节)
        • 认证流程(验证访问系统用户的身份)
        • 鉴权流程(判断用户访问资源的权限)
        相关产品与服务
        云数据库 Redis
        腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档