• 将 Shiro 作为应用的权限基础


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

    前言

    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 的使用示例,可以下载文中使用的源代码。

    本文代码的开发环境:

    • Jsecurity 0.9
    • Grails 1.2.0
    • Grails Shiro Plugin 1.0.1
    • SpringSource Tool Suite 2.3

    Shiro 是一个强大而灵活的开源安全框架,能够非常清晰的处理认证、授权、管理会话以及密码加密。如下是它所具有的特点:

    1. 易于理解的 Java Security API;
    2. 简单的身份认证(登录),支持多种数据源(LDAP,JDBC,Kerberos,ActiveDirectory 等);
    3. 对角色的简单的签权(访问控制),支持细粒度的签权;
    4. 支持一级缓存,以提升应用程序的性能;
    5. 内置的基于 POJO 企业会话管理,适用于 Web 以及非 Web 的环境;
    6. 异构客户端会话访问;
    7. 非常简单的加密 API;
    8. 不跟任何的框架或者容器捆绑,可以独立运行。

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

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

    Spring Security —目前是 Java 安全框架领域当之无愧的老大,已经非常成熟了;如果使用 Spring 框架,可以首选 Spring Security,但是对于单应用来说,Shiro 更显简单方便。

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

    整体架构

    首先,我们来看看的 Shiro 的整体架构,见下图:

    图 1. 整体架构
    图 1. 整体架构

    从上图可以看出,Shiro 主要有四个组件:

    1. SecurityManager

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

    2. Authenticator

      对“Who are you ?”进行核实。通常涉及用户名和密码。

      这个组件负责收集 principals 和 credentials,并将它们提交给应用系统。如果提交的 credentials 跟应用系统中提供的 credentials 吻合,就能够继续访问,否则需要重新提交 principals 和 credentials,或者直接终止访问。

    3. Authorizer

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

    4. Session Manager

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

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

    安全模型

    从 Shiro 的框架图,已经能够体会到这个工具的简单了。下面让我们来看看 Shiro 是如何工作的。先了解一下它的安全模型吧!见下图:

    图 2. 安全模型
    图 2. 安全模型

    上图中,涉及了 Shiro 的五个概念:

    • Subject 是安全领域术语,除了代表人,它还可以是应用。在单应用中,可将其视为 User 的同义词。
    • Principal 是 Subject 的标识,一般情况下是唯一标识,比如用户名。
    • Role 和 Permission 分别代表了不同粒度的权限,从上图中可以看出 Role 的粒度更大些,Permission 代表了系统的原子权限,比如数据的修改、删除权限。对于简单的权限应用,可以不需要 Permission。
    • Realm 是一个执行者,负责真正的认证和鉴权。

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

    1. role 没有实质内容,只是代表一组 permission,目的是为了管理的方便,一般都是动态定义;
    2. permission 一般都是预先定义好的,不允许动态改变,除非源代码改动,它才会变化,它是整个安全模块的基础;
    3. 要使 permission 也能动态定义,并非不可能,但是这将使鉴权非常复杂,甚至可能导致鉴权语句遍布整个程序,得不偿失;
    4. 当然有一个例外:如果知道 permission 动态定义的规则和鉴权规则,如 Grails 的 fileter 中“${controllerName}:${actionName}:${params.id}”也可实现 permission 的动态定义

    关键概念类

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

    图 3. 关键类
    图 3. 关键类

    AuthenticationToken 和 AuthenticationInfo

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

    RememberMe

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

    Credentials 和 CredentialsMatcher

    Credentials 是 Subject 的证书,在认证时使用,最常用的就是 password。在通常情况下,为了安全起见,Subject 的 credentials 都需要加密保存,于是 CredentialsMatcher 的作用就体现出来了,见下图:

    图 4. CredentialsMatcher 的作用
    图 4. CredentialsMatcher 的作用

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

    PAM= Pluggable Authentication Modules

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

    AuthorizationInfo

    可以看成是 Role + Permission 的组合体。

    PermissionResolver 和 Permission

    它们之间的关系如下:

    图 5. 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 需要注意如下内容:

    1. 权限的比较实际是字符串的比较,只不过是考虑到了字符串的分级
    2. 字符串的分级划分完全由使用者自己决定,Shiro 的惯例是 3 级:资源 : 操作 : 实例。
    3. 字符串的使用必须一致,分隔符之间不要有空格,避免无意间引入的不一致。如:定义使用“file : create, update : 1”,而验证使用“file : update”,那么分解之后一个是“ update ”,一个是“ update”,因空格而引起不等。

    Realm

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

    图 6. 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 的作用
    图 7. Filter 的作用

    在实际使用时,须注意:

    1. web.xml 中只需配置 JSecurityFilter。对于 Spring 应用,则使用 SpringJSecurityFilter;
    2. 子 filter 作为主 filter 的配置参数值出现,特点是:顺序相关
      • 对于多个 URL,验证顺序是由上至下,类似 Exception 的匹配。因此,使用顺序应该是由细到粗。
      • 对于同一 URL,子 filter 的验证顺序是从左至右的 AND 操作。
    3. 如果配置值中含有分隔符,如 Permission,就需要使用引号来转义。

    Subject

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

    Configuration

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

    图 8. 配置关系
    图 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 页面


    来源:http://www.ibm.com/developerworks/cn/opensource/os-cn-shiro/index.html





  • 相关阅读:
    流浪西邮之寻找火石碎片
    给你一个666
    似魔鬼的步伐
    括号匹配2019
    挑剔程度
    到底有到少个小和尚?
    获取任务栏所有正在运行程序
    EXTJS4创建多级菜单
    关于时间的一些理解
    kof97调隐藏人物
  • 原文地址:https://www.cnblogs.com/jeffen/p/6208256.html
Copyright © 2020-2023  润新知