将 Shiro 做为应用的权限基础

    Shiro 是 Java 世界中新近出现的权限框架,较之 JAAS 和 Spring Security,Shiro 在保持强大功能的同时,还在简单性和灵活性方面拥有巨大优点。本文介绍了 Shiro 的关键概念和权限模型,同时给出了 Shiro 以及 Grails Shiro Plugin 的使用示例。在阅读本文的过程当中,读者能够充分的体会到 Shiro 的魅力。web

前言数据库

    Shiro 是 JAVA 世界中新近出现的权限框架,较之 JAAS 和 Spring Security,Shiro 在保持强大功能的同时,还在简单性和灵活性方面拥有巨大优点。本文就带领读者一睹 Shiro 的风采。缓存

    可能你们早先会见过 J-security,这个是 Shiro 的前身。在 2009 年 3 月初以前,这个安全框架叫作 J-security,因为某些缘由,改名为 Shiro(或者 Ki,意为 Fortress),是 Apache 的孵化项目,鉴于本文编写时 Shiro 的尚未正式发布的版本,本文使用的是 Jsecurity 的稳定版本 0.9,本文中 Shiro 等同于 Jsecurity。安全

    本文将涉及 Shiro 的总体框架、安全模型、关键概念类,同时给出了 Shiro 以及 Grails Shiro Plugin 的使用示例,能够下载文中使用的源代码。服务器

本文代码的开发环境:session

  • Jsecurity 0.9架构

  • Grails 1.2.0框架

  • Grails Shiro Plugin 1.0.1ide

  • SpringSource Tool Suite 2.3工具

    Shiro 是一个强大而灵活的开源安全框架,可以很是清晰的处理认证、受权、管理会话以及密码加密。以下是它所具备的特色:

  • 易于理解的 Java Security API;

  • 简单的身份认证(登陆),支持多种数据源(LDAP,JDBC,Kerberos,ActiveDirectory 等);

  • 对角色的简单的签权(访问控制),支持细粒度的签权;

  • 支持一级缓存,以提高应用程序的性能;

  • 内置的基于 POJO 企业会话管理,适用于 Web 以及非 Web 的环境;

  • 异构客户端会话访问;

  • 很是简单的加密 API;

  • 不跟任何的框架或者容器捆绑,能够独立运行。

目前还有其余出现较早的安全框架,好比 JAAS,Spring Security。

    JAAS —面世的时间最先,可是鉴于其在使用上有很大的限制,不多有人真正的使用它。能够说它不是一个好的应用程序级别的安全框架;

    Spring Security —目前是 Java 安全框架领域当之无愧的老大,已经很是成熟了;若是使用 Spring 框架,能够首选 Spring Security,可是对于单应用来讲,Shiro 更显简单方便。

下面就开始咱们的 Shiro 之旅吧!

总体架构

首先,咱们来看看的 Shiro 的总体架构,见下图:

图 1. 总体架构

从上图能够看出,Shiro主要有四个组件:

一、SecurityManager

    典型的Facade,Shiro经过它对外提供安全管理的各类服务。

二、Authenticator

    对"Who are you"实现核实。一般涉及用户名和密码。

    这个组件负责收集principals和credentials,并将它们提交给应用系统。吐过提交的credentials跟应用系统中提供的credentials温和,就能继续访问,不然须要从新提交principals和credentials,或者终止访问。

三、Authorizer

    身份验证经过后,由这个组件对登录人员进行访问控制的筛查,好比"Who can do what",或者"Who can 都 which action"。Shiro采用基于Realm的方法,即用户(又称为Subject)、用户组、角色和permission的聚合体。

四、SessionManager

    这个组件保证了异构客户端的访问,配置简单,它是基于POJO/J2SE的,不跟任何的客户端或者协议绑定。

    Shiro的认证和签证能够经过JDBC、LDAP 或者 Active Directory 来访问数据库、目录服务器或者 Active Directory 中的人员以及认证 / 签权信息。SessionManager 经过会话 DAO 能够将会话保存在 cache 中,或者固化到数据库或文件系统中。

安全模型

从Shiro的框架图,已经可以体会到这个工具的简单。下面让咱们看看Shiro是如何工做的。

图 2. 安全模型

上图,设计了Shiro的五个概念:

一、Subject是安全领域的术语,除了表明人,他还能够是应用。在单应用中,可将其设为User的同义词。

二、Principle是Subject的标识,通常状况下是惟一的标识,好比用户名。

三、Role和Permission分别表明了不一样粒度的权限,从上图能够看出Role的粒度更大些,Permission表明了系统的原子权限,好比数据的修改、删除权限。对于简单的权限应用,能够不须要Permission。

四、Realm是一个执行者,负责真正的认证和鉴权。

实现应用的安全模式的关键在于:定义合适的role和permission,这就须要遵循以下原则:

一、role没有实质内容,只是表明了一种permission,目的是为了管理的方便,通常都是动态定义;

二、permission通常都是预先定义好的,不容许动态改变,除非源码改动,它才会变化,它是整个安全模块的基础;

三、要是permission也能动态定义,并不是不可能,可是这将鉴权很是复杂,甚至可能致使鉴权语句遍及整个程序,得不偿失;

四、固然有一个例外的:若是知道permission动态定义的规则和鉴权规则,如Grail的filter中“${controllerName}:${actionName}:${params.id}”也可实现permission的动态定义。

关键概念类

·理解 Shiro 的架构和安全模型了,咱们来看看更具体些的内容。下图显示了 Shiro 中的关键概念类(参考资料 -- JSecurity Mini Guide)。

图 3. 关键类

AuthenticationToken 和 AuthenticationInfo

前者在认证前使用,描述认证所需的信息,最经常使用的就是 username 和 password 对;后者在认证后使用,内容同前,可是表示已经通过认证的信息。

RememberMe

表明的是一种可能状态,并不表示该 Subject 已经通过了认证。对于一些普通的操做,这种可能状态并没有大碍,但一旦涉及安全敏感的操做,必须通过认证。

Credentials 和 CredentialsMatcher

Credentials 是 Subject 的证书,在认证时使用,最经常使用的就是 password。在一般状况下,为了安全起见,Subject 的 credentials 都须要加密保存,因而 CredentialsMatcher 的做用就体现出来了,见下图:

图 4. CredentialsMatcher 的做用

这里 CredentialsMatcher 须要将加密后的证书跟用户登陆时提供的证书进行比对,完成认证的过程。

PAM= Pluggable Authentication Modules

在有多个 Realm 的时候使用。由认证策略决定认证结果,即 PAM= Relams + 认证策略。通常的策略有 3 种:AllSuccessful、AtLeastOneSuccessful 和 FirstSuccessful。

AuthorizationInfo

能够当作是 Role + Permission 的组合体。

PermissionResolver 和 Permission

它们之间的关系以下:

图 5. PermissionResolver 和 Permission 的关系

    在 Shiro 中,权限被转化为一种字符串描述(字符串分级表示,称之为 WildcardPermission),从而将权限转化为相似于对象 equals 的操做(Shiro 中的 implies 方法)。

内置的权限有 2 个:

  • AllPermission,老是返回 true

  • WildcardPermission,权限字符串的表示方式。

    这里重点声明一下。WildcardPermission 是 Shiro 的精妙之处,咱们能够将权限表示成字符串,这样对权限的控制能够不拘泥于物理存储,好比对 messagge 类具备修改和删除权限能够标识为:message:update,delete:*,其中‘ * ’表示全部;第一级分隔符为‘ : ’;第二级分隔符为‘ , ’,而对于权限字符串的解释彻底能够由应用本身来定。

    若是要比较权限字符串,可使用 permission1.implies(permission2),它分别比较对应位置的字符串,在以下状况中,结果会返回 true:

  • permission1 中的子串有 * 或 permission1 子串 ==permission2 子串;

  • permission1 无子串,permission2 有;

  • permission1 有子串,permission2 无,permission1 的全部子串都是 *。

总的说来,Shiro 中的 Permission 须要注意以下内容:

  • 权限的比较实际是字符串的比较,只不过是考虑到了字符串的分级

  • 字符串的分级划分彻底由使用者本身决定,Shiro 的惯例是 3 级:资源 : 操做 : 实例。

  • 字符串的使用必须一致,分隔符之间不要有空格,避免无心间引入的不一致。如:定义使用“file : create, update : 1”,而验证使用“file : update”,那么分解以后一个是“ update ”,一个是“ update”,因空格而引发不等。

Realm

    这是一个实际访问安全实体的组件,通常是应用相关的,跟数据源的关系是 1-1。它负责完成认证和鉴权,getAuthenticationInfo 表明了 login 的尝试,鉴权方法则由 Authorizer 继承而来。此处也体现了 Shiro 代码的另外一个特色,经过继承来扩充功能。以经常使用的 JdbcRealm 为例,其继承链以下:

图 6. JdbcRealm 的继承链

Session

    它关联一个 Subject 的上下文,其做用相似于在 HttpSession 中保存用户标识,session 一旦过时,则从新登陆。Shiro 的 Session 是独立的,其目的是作到环境无关性。为了利用 Web 环境中,Shiro 实现了一个直接使用 HttpSession 的 WebSession。

SecurityManager

    这是一个 Façade 接口,=Authenticator + Authorizer + SessionFactory。在总体框架图中已经看到了它在 Shiro 中所处的位置。其特色同 Realm,同样是使用继承不断地扩充功能。对于 Web 应用通常使用 DefaultWebSecurityManager。

Filter

    在 Web 环境下使用 filter 进行认证和权限检查是毋庸置疑的,而 Shiro 的特色则在于由一个主 Filter 将一群子 filter 串起来:

图 7. Filter 的做用

在实际使用时,须注意:

一、web.xml 中只需配置 JSecurityFilter。对于 Spring 应用,则使用 SpringJSecurityFilter;

二、子 filter 做为主 filter 的配置参数值出现,特色是:顺序相关

  • 对于多个 URL,验证顺序是由上至下,相似 Exception 的匹配。所以,使用顺序应该是由细到粗。

  • 对于同一 URL,子 filter 的验证顺序是从左至右的 AND 操做。

三、若是配置值中含有分隔符,如 Permission,就须要使用引号来转义

Subject

    subject 表明了一个用户的状态和操做,它提供了全部安全相关的操做,包括认证和签权。能够将其视为另外一种形式的 Façade。缺省实现是将这些操做委派给其内部包含的 SecurityManager。

Configuration

    configuration 负责将全部这些组件串起来,最终建立 SecurityManager。在 Shiro 中,缺省格式是 ini。整个配置关系以下图:

图 8. 配置关系

其中:

    JSecurityFilter 建立 Configuration 实例,并将 ini 参数值传给 Configuation。在 Spring 环境中,分别使用 SpringJSecurityFilter 和 SpringIniWebConfiguration。

    Configuration 实际就是 SecurityManager 的 Factroy,对 SpringIniWebConfiguration 而言,它须要知道 SecurityManager 的 BeanName,该值由 SpringJSecurityFilter 的初始化参数“securityManagerBeanName”值决定。即 SpringJSecurityFilter,实际有两个初始化参数:

    config,是 ini 配置文件内容

    securityManagerBeanName,是 SecurityManager 的 BeanName

SecurityUtils

这是 Shiro 中最重要的工具类,由它能够方便地得到 Subject 和 SecurityManager。

杂项

  • AOP,提供 AOP 方面的支持,实现对某个类某个方法的拦截,从而使权限控制延伸至类的方法。

  • Cache,提供缓存支持

  • Codec,提供编码方面的支持

  • Crypto,提供加密支持

  • IO,从多个资源位置读写原始数据

  • JNDI,提供 jndi 支持

  • util,工具类支持

  • 标签类,用于 Web 页面

注:原文还有基于groovy的例子,在此没有转载。

相关文章
相关标签/搜索