Apache Shiro权限管理框架介绍
Apache Shiro的官网地址以下:前端
http://shiro.apache.org/java
Apache Shiro是一个简单易用且强大而灵活的开源Java安全框架,如下简称Shiro。它干净利落地处理身份认证、受权以及企业会话管理和加密。Shiro拥有易于理解的API,你能够快速且容易地使用它来保护任何应用程序——从最小的移动应用程序到最大的web和企业应用程序。web
Shiro权限基础概念:算法
- 安全实体:就是被权限系统保护的对象,好比工资数据。
- 权限:就是须要被校验的行为,好比查看、修改等。
- 分配权限:把对某些安全实体的某些权限分配给某些人员。是向数据库里面添加数据、或是维护数据的过程
- 权限验证(权限匹配):判断某我的员或程序对某个安全实体是否拥有某个或某些权限。从数据库中获取相应数据进行匹配的过程。
- 权限的继承性:若是多个安全实体存在包含关系,而某个安全实体没有权限限制,则它会继承包含它的安全实体的相应权限。
- 权限的最近匹配原则:若是多个安全实体存在包含关系,而某个安全实体没有权限限制,那么它会向上寻找并匹配相应权限限制,直到找到一个离这个安全实体最近的拥有相应权限限制的安全实体为止。若是把整个层次结构都寻找完了都没有匹配到相应权限限制的话,那就说明全部人对这个安全实体都拥有这个相应的权限限制。
Shiro 能作什么:数据库
- 认证:验证用户的身份
- 受权:对用户执行访问控制:判断用户是否被容许作某事
- 管理:在任何环境下使用 Session API,即便没有 Web 或EJB 容器。
- 加密:以更简洁易用的方式使用加密功能,保护或隐藏数据防止被偷窥
- Realms:汇集一个或多个用户安全数据的数据源
- 单点登陆(SSO)功能:为没有关联到登陆的用户启用 "Remember Me“ 服务
Shiro 的主要功能架构图:

从上图中能够看到 Shiro 的四大核心部分:apache
- Authentication(身份验证):简称为“登陆”,即证实用户是谁。
- Authorization(受权):访问控制的过程,即决定是否有权限去访问受保护的资源。
- Session Management(会话管理):管理用户特定的会话,即便在非 Web 或 EJB 应用程序。
- Cryptography(加密):经过使用加密算法保持数据安全
其中 Shiro 还提供了如下扩展:缓存
- Web Support:主要针对web应用提供一些经常使用功能。
- Caching:缓存可使应用程序运行更有效率。
- Concurrency:多线程相关功能。
- Testing:帮助咱们进行测试相关功能
- "Run As":一个容许用户假设为另外一个用户身份(若是容许)的功能,有时候在管理脚本颇有用。
- "Remember Me" :记住用户身份,提供相似购物车功能。
Shiro 概念层架构的 3 个核心组件图:

- Subject :正与系统进行交互的人,或某一个第三方服务。全部 Subject 实例都被绑定到(且这是必须的)一个SecurityManager 上。
- SecurityManager:Shiro 架构的心脏,用来协调内部各安全组件,管理内部组件实例,并经过它来提供安全管理的各类服务。当 Shiro 与一个 Subject 进行交互时,实质上是幕后的 SecurityManager 处理全部繁重的Subject 安全操做,能够将其概念比做为是SpringMVC中的前端控制器。
- Realms :本质上是一个特定安全的 DAO。当配置 Shiro 时,必须指定至少一个 Realm 用来进行身份验证或受权。Shiro 提供了多种可用的 Realms 来获取安全相关的数据。如关系数据库(JDBC),INI 及属性文件等。能够定义本身 Realm 实现来表明自定义的数据源。
Shiro 架构图:

- Authenticator :执行对用户的身份验证(登陆)的组件。Authenticator 从一个或多个 Realm 中得到数据以验证用户的身份。 若存在多个realm,则接口 AuthenticationStrategy 会肯定什么样算是验证成功(例如,若是一个 Realm 成功,而其余的均失败,是否登陆成功)。
- Authorizer :权限管理器,主要用于用户的访问控制,验证用户可否访问应用中的受保护资源。
- SessionManager :session管理器,可在任何应用或架构层一致地使用 Session API
- SessionDAO:SessionManager 执行 Session 持久化(CRUD)操做。
- CacheManager :对 Shiro 组件提供缓存支持。
- Cryptography:Shiro 的 API 大幅度简化 Java API 中繁琐的密码加密
- Realms:Shiro 经过 Realms 来获取相应的安全数据
Shiro 配置基础
Shiro 被设计成可以在任何环境下工做,从简单的命令行应用程序到企业群集应用。因为环境的多样性,使得 Shiro 可使用多种配置机制。安全
users:cookie
- ini 配置:ini 其实是一个文本配置,包含了由惟一命名的项来组织的键/值对。
- [users] 部分容许定义一组静态的用户账户
- 每行的格式:
username = password, roleName1, roleName2, …
roles:session
- [roles] 部分容许把定义在 [users] 部分中的角色与权限关联起来
- 每行的格式:
rolename = permissionDefinition1, permissionDefinition2, …
- permissionDefinition 是一个任意的字符串,但大多数人将会使用符合 org.apache.shiro.authz.permission.WildcardPermission 格式的字符串。
注意:
- 若是一个独立的 permissionDefinition 须要被内部逗号分隔(例如,printer:5thFloor:print,info),则须要用户双引号环绕该定义,以免错误解析。
- 若是角色不想关联权限,则不须要在 [roles] 部分把它们列出来。只需定义在 [user] 部分中定义角色名就足以建立尚不存在的角色。
- 仅定义非空的 [users] 或 [roles] 部分就将自动地触发org.apache.shiro.realm.text.IniRealm 实例的建立
Shiro 身份认证: Authentication
Authentication :身份验证——经过提交用户的身份和凭证给 Shiro,以判断它们是否和应用程序预期的相匹配。
基本概念:
- Principals(身份):Subject 的 identifying attributes(标识属性)。好比咱们登陆提交的用户名。
- Credentials(凭证):用来做为一种起支持做用的证据,此证据包含×××明。好比咱们登陆提供的密码
认证的基本步骤:
- 收集Subjects 提交的Principals(身份)和Credentials(凭证);
- 提交Principals(身份)和Credentials(凭证)进行身份验证;
- 若是提交成功,则容许访问,不然从新进行身份验证或者阻止访问。
- AuthenticationToken:Shiro 中表明提交的 Principals(身份) 和 Credentials (凭证) 的身份验证系统的最基本接口。
- UsernamePasswordToken :AuthenticationToken 的接口的实现类,支持最多见的用户名/密码的身份验证
提交用户名/密码进行认证:
Subject currentUser = SecurityUtils.getSubject();
currentUser.login(token);
处理认证成功和失败
- 认证成功:没有返回,也没有异常,经过。
- 认证失败,拋出异常,能够在程序中捕获并处理
认证顺序:

认证过程:

Step 1:应用程序代码调用 Subject.login 方法,传递建立好的包含终端用户的 Principals(身份)和 Credentials(凭证)的 AuthenticationToken 实例
Step 2:Subject 实例,一般为 DelegatingSubject(或子类)委托应用程序的 SecurityManager 经过调用 securityManager.login(token) 开始真正的验证。
Step 3:SubjectManager 接收 token,调用内部的 Authenticator 实例调用 authenticator.authenticate(token)。 Authenticator 一般是一个 ModularRealmAuthenticator 实例,支持在身份验证中协调一个或多个Realm 实例。
Step 4:若是应用程序中配置了一个以上的 Realm,ModularRealmAuthenticator 实例将利用配置好的AuthenticationStrategy 来启动 Multi-Realm 认证尝试。在Realms 被身份验证调用以前,期间和之后,AuthenticationStrategy 被调用使其可以对每一个Realm 的结果做出反应。
Step 5:每一个配置的 Realm 用来帮助看它是否支持提交的AuthenticationToken。若是支持,那么支持 Realm 的 getAuthenticationInfo 方法将会伴随着提交的 token 被调用。getAuthenticationInfo 方法有效地表明一个特定 Realm 的单一的身份验证尝试。
Shiro 受权
受权:又称访问控制—控制谁有权限在应用程序中作什么。在受权中,须要了解几个关键的对象:Subject 主体、Resource 资源、Permissions 权限、Role 角色:
- Subject 主体:访问应用的用户,在 Shiro 中使用 Subject 表明该用户,用户须要受权后才能访问相应的资源
- Resource 资源:在应用中用户访问的任何东西,例如:jsp、接口、图片等,都属因而资源
- Permissions 权限:Shiro 安全机制最核心的元素。它在应用程序中明确声明了被容许的行为。一个格式良好的权限声明能够清晰表达出用户对该资源拥有的权限。在 Shiro 中主要经过通配符表达式来完成权限的描述
- Role 角色:一个命名的实体, 一般表明一组行为或职责。 这些行为演化为在一个应用中能或者不能作的事情。角色一般分配给用户账户。一个角色拥有一个权限的集合。受权验证时,须要判断当前角色是否拥有指定的权限。这种角色权限能够对该角色进行详细的权限描述。 Shiro官方推荐使用这种方式
受权检查的例子:用户是否能访问某个网页,编辑数据,或打使用这台打印机
受权的三要素:权限、角色和用户 。
须要在应用程序中对用户和权限创建关联:一般的作法是将权限分配给角色,而后将角色分配给一个或多个用户。
Shiro的三种受权方式:
- 编写代码:在 Java 代码中用像 if 和 else 块的结构执行受权检查。
- JDK 的注解:能够添加受权注解给 Java 方法
- JSP 标签库:能够控制基于角色和权限的JSP 页面输出。
Shiro 受权顺序图:

时序图:

- Step 1:应用程序或框架代码调用任何 Subject 的
hasRole*
, checkRole*
, isPermitted*
,或者checkPermission*
方法的变体,传递任何所需的权限
- Step 2:Subject 的实例—一般是 DelegatingSubject(或子类),调用securityManager 的对应的方法。
- Step 3:SecurityManager 调用
org.apache.shiro.authz.Authorizer
接口的对应方法。默认状况下,authorizer 实例是一个 ModularRealmAuthorizer 实例,它支持协调任何受权操做过程当中的一个或多个Realm 实例。
- Step 4:每一个配置好的 Realm 被检查是否实现了相同的 Authorizer 接口。若是是,Realm 各自的
hasRole*
, checkRole*
, isPermitted*
,或 checkPermission*
方法将被调用。
Shiro 基础语法:Permissions的声明方式
基础语法之简单的字符串:
- 即用简单的字符串来表示一个权限,如:
user
(至关于:user:*
)
基础语法之多层次管理:
- 例如:
user:query、user:edit
- 多个值:每一个部件可以保护多个值。所以,除了授予用户
user:query
和 user:edit
权限外,也能够简单地授予他们一个:user:query, edit
- 还能够用
*
号代替全部的值,如:user:*
, 也能够写:*:query
,表示某个用户在全部的领域都有 query 的权限
基础语法之实例级访问控制:
- 这种状况一般会使用三个部件:域、操做、被付诸实施的实例。如:
user:edit:manager
- 也可使用通配符来定义,如:
user:edit:*、user:*:*、user:*:manager
- 部分省略通配符:缺乏的部件意味着用户能够访问全部与之匹配的值,好比:
user:edit
等价于 user:edit :*
、user 等价于 user:*:*
注意:通配符只能从字符串的结尾处省略部件,也就是说 user:edit 并不等价于 user:*:edit
Shiro 注销
logout(注销):currentUser.logout();
- 调用 logout() 方法时,现有 Session 将失效,并且身份将失去关联(在Web 应用程序中,RememberMe cookie 将被删除)。
- 在 Subject 注销后,该 Subject 的实例被再次认为是匿名的。
注意:WEB 应用程序记住身份每每依靠 Cookie,然而Cookie 只能在 Response 被返回后被删除,因此建议在调用subject.logout() 后当即向终端重定向一个新的视图或页面。这样即能保证与安全相关的 Cookie 都能像预期的同样被删除。
Realm
- Realm:访问应用程序安全数据(如用户、角色及权限)的组件。
- Realm 一般和数据源是一对一的对应关系,如关系数据库、文件系统或其余相似资源。Realm 实质上就是一个访问安全数据的 DAO。
- 数据源一般存储身份验证数据(如密码的凭证)以及受权数据(如角色或权限),因此每一个Realm 都可以执行身份验证和受权操做。
Realms的认证明现
Shiro 的认证过程由 Realm 执行,SecurityManager 会调用 org.apache.shiro.realm.Realm
的 getAuthenticationInfo(AuthenticationToken token)
方法
实际开发中,一般会提供 org.apache.shiro.realm.AuthenticatingRealm
的实现类,并在该实现类中提供doGetAuthenticationInfo(AuthenticationToken token)
方法的具体实现
- 检查提交的进行认证的令×××信息
- 根据令×××信息从数据源(一般为数据库)中获取用户信息
- 对用户信息进行匹配验证。
- 验证经过将返回一个封装了用户信息的 AuthenticationInfo 实例。
- 验证失败则抛出 AuthenticationException 异常信息。
Shiro权限拦截
Shiro和Spring Security同样,都是基于过滤器来实现权限拦截的。shiro中默认的过滤器:

过滤器链:

过滤器类图:

Shiro会话管理
Shiro提供了完整的企业级会话管理功能,不依赖于底层容器(如Tomcat),不论是J2SE仍是J2EE环境均可以使用,提供了会话管理,会话事件监听,会话存储/持久化,容器无关的集群,失效/过时支持,对Web的透明支持,SSO单点登陆的支持等特性。
建议在开发中,Controller层使用原生的HttpSession对象,在Service层中使用Shiro提供的Session对象。若是在Service层中使用HttpSession对象,那么属于侵入式,并不建议这么作。Shiro提供的Session可以很好的解决这个问题。
会话管理相关类图:

Shiro权限缓存
缓存是×××能的重要手段,对同一批数据进行屡次查询时, 第一次查询走数据库,查询数据后,将数据保存在内存中,第二次之后查询能够直接从内存获取数据,从而不须要和数据库进行交互。这样减小了系统查询数据库的次数,提高了性能。
缓存适合那些常常不变更的数据,好比系统中用户的信息和权限不会常常改变,特别适合缓存起来供下次使用。其中咱们的权限信息就是不怎么会改变的,对权限信息进行缓存能够提升咱们系统的性能。不过 Shiro 自身不实现缓存,而是提供缓存接口,让其余第三方实现,默认支持EhCache和MapCache缓存。
Shiro 缓存相关的类图:
