初步了解shrio
- 什么是shrio?
- Shrio四个主要功能?
- 为什么使用shrio?
- 核心概念:Subject、SecurityManager 和 Realms
- 验证(Authentication)
- 授权(Authorization)
- Session Management
- Cryptography
- Web Support
- URL-Specific Filter Chains
- Web Session Management
- Framework Limitations(框架限制)
- 它与 Spring Security 相比如何?
·
什么是shrio?
Apache Shiro是一个功能强大且易于使用的 Java 安全框架,它执行身份验证、授权、加密和会话管理,可用于保护任何应用程序 -从命令行应用程序、移动应用程序到最大的 Web 和企业应用程序。。
Shrio四个主要功能?
身份验证(Authentication)校验用户身份
授权(Authorization)访问控制
密码学 (Cryptography)保护或隐藏数据不被窥探
会话管理 (Session Management)
为什么使用shrio?
1、易于使用——对于新手程序员可以直接开始使用它。
2、全面——其他安全框架没有shrio声称的范围广度,它能满足你所需要的“一站式服务”安全需求。
3、灵活——Apache Shiro 可以在任何应用程序环境中工作。虽然它可以在 Web、EJB 和 IoC 环境中工作,但它不需要它们。Shiro 也没有强制要求任何规范,甚至没有很多依赖项。
4、Web Capable —— Apache Shiro 具有出色的 Web 应用程序支持,允许您基于应用程序 URL 和 Web 协议(例如 REST)创建灵活的安全策略,同时还提供一组 JSP 库来控制页面输出。
5、易于集成—— Shiro 干净的 API 和设计模式使其易于与许多其他框架和应用程序集成。 Shiro 能夠与 Spring、Grails、Wicket、Tapestry、Mule、Apache Camel、Vaadin 等框架无缝集成。
核心概念:Subject、SecurityManager 和 Realms
Subject
是一个安全术语,基本上表示“当前正在执行的用户”。它只是不被称为“用户”,因为“用户”这个词通常与人类相关联。在安全世界中,“主题”一词可以指人类,也可以指第 3方进程、守护进程帐户或任何类似的东西。它只是意味着“当前正在与软件交互的东西”。
获得主题后,您立即可以访问 90% 的当前用户想要对 Shiro 执行的所有操作,例如登录、注销、访问他们的会话、执行授权检查等等。
(获取subject:currentUser = SecurityUtils.getSubject(); )
SecurityManager
SecurityManager 管理所有用户的安全操作。它是 Shiro 架构的核心。
Realms
Realm 充当 Shiro 和应用程序安全数据之间的“桥梁”或“连接器”。也就是说,当需要与安全相关数据(如用户帐户)进行实际交互以执行身份验证(登录)和授权(访问控制)时,Shiro 会从为应用程序配置的一个或多个Realm中查找其中的许多内容。从这个意义上说,Realm 本质上是一个特定于安全性的DAO:它封装了数据源的连接细节,并根据需要使关联的数据可供 Shiro 使用。配置 Shiro 时,您必须指定至少一个 Realm 用于身份验证和/或授权。可以配置多个 Realm,但至少需要一个。
验证(Authentication)
身份验证是验证用户身份的过程,通常是一个三步过程。
1、收集用户的识别信息,称为主体,以及支持身份证明,称为凭据。
2、向系统提交主体和凭据。
3、如果提交的凭据与系统对该用户身份(subject)的期望匹配,则认为该用户已通过身份验证。如果它们不匹配,则不认为用户已通过身份验证。
Shiro 以简单直观的方式支持相同的工作流程。正如我们所说,Shiro 有一个以 Subject 为中心的 API——几乎你在运行时用 Shiro 做的所有事情都是通过与当前正在执行的 Subject 交互来实现的。因此,要登录 Subject,您只需调用其 login 方法,传递一个 AuthenticationToken 实例,该实例代表提交的principals 和credentials (在本例中为用户名和密码)。
授权(Authorization)
授权本质上是访问控制——控制用户可以在应用程序中访问的内容,例如资源、网页等。大多数用户通过使用角色和权限等概念来执行访问控制。也就是说,通常根据分配给用户的角色和/或权限来允许用户做某事或不做某事。然后,您的应用程序可以根据对这些角色和权限的检查来控制公开哪些功能。如您所料,Subject API 允许您非常轻松地执行角色和权限检查。例如,以下 中的代码片段显示了如何检查 Subject 是否已被分配了某个角色。
角色检查
if ( subject.hasRole(“administrator”) ) {
//show the ‘Create User’ button
} else {
//grey-out the button?
}
权限检查是执行授权的另一种方式。上例中的角色检查存在一个重大缺陷:您无法在运行时添加或删除角色。您的代码是使用角色名称硬编码的,因此如果您更改角色名称和/或配置,您的代码就会被破坏!如果您需要能够在运行时更改角色的含义,或者根据需要添加或删除角色,则必须依赖其他东西。
为此,Shiro 支持其权限概念。权限是功能的原始声明,通过让权限反映应用程序的原始功能,您只需更改权限检查您何时更改应用程序的功能。反过来,您可以在运行时根据需要将权限分配给角色或用户。
权限检查
if ( subject.hasRole(“administrator”) ) {
//show the ‘Create User’ button
} else {
//grey-out the button?
}
这样,任何分配了“user:create”权限的角色或用户都可以单击“Create User”按钮,这些角色和分配甚至可以在运行时更改,为您提供非常灵活的安全模型。
权限检查
if ( subject.isPermitted(“user:create”) ) {
//show the ‘Create User’ button
} else {
//grey-out the button?
}
此示例表明,如果需要,您可以控制对单个资源的访问,甚至可以控制到非常细粒度的实例级别。如果您愿意,您甚至可以发明自己的权限语法。有关更多信息,请参阅Shiro 权限文档。最后,就像身份验证一样,上述调用最终会到达 SecurityManager,SecurityManager 将咨询一个或多个 Realms 以做出访问控制决策。这允许 Realm 在必要时响应身份验证和授权操作。
Session Management
Apache Shiro 提供了安全框架领域中独一无二的东西:一致的 Session API 可用于任何应用程序和任何架构层。也就是说,Shiro 为任何应用程序启用了会话编程范式 - 从小型守护程序独立应用程序到最大的集群 Web 应用程序。这意味着希望使用会话的应用程序开发人员不再被迫使用 Servlet 或 EJB 容器(如果他们不需要它们)。或者,如果使用这些容器,开发人员现在可以选择在任何层中使用统一且一致的会话 API,而不是使用 servlet 或 EJB 特定的机制。
Shiro 会话最重要的好处之一是它们独立于容器。这具有微妙但极其强大的含义。例如,让我们考虑会话集群。有多少种特定于容器的方法来集群会话以实现容错和故障转移?Tomcat 的处理方式与 Jetty 不同,Jetty 的处理方式与 Websphere 等不同。但是使用 Shiro 会话,您可以获得独立于容器的集群解决方案。Shiro 的架构允许可插拔的 Session 数据存储,例如企业缓存、关系数据库、NoSQL 系统等。这意味着您可以配置一次会话集群,无论您的部署环境如何 - Tomcat、Jetty、JEE 服务器或独立应用程序,它都将以相同的方式工作。
Shiro 会话的另一个好处是,如果需要,可以跨客户端技术共享会话数据。例如,如果需要,Swing 桌面客户端可以参与同一个 Web 应用程序会话 - 如果最终用户同时使用这两者,则很有用。那么如何在任何环境中访问主题的会话呢?有两种 Subject 方法,如下例所示。
Session session = subject.getSession();
Session session = subject.getSession(boolean create);
这些方法在概念上与 HttpServletRequest API 相同。第一种方法将返回 Subject 的现有 Session,或者如果还没有,它将创建一个新的并返回它。第二种方法接受一个布尔参数,该参数确定如果新 Session 尚不存在,是否会创建它。一旦你获得了 Subject 的 Session,你就可以像使用 HttpSession 一样使用它了。Shiro 团队认为 HttpSession API 最适合 Java 开发人员,当然,最大的不同是您可以在任何应用程序中使用 Shiro Sessions,而不仅仅是 Web 应用程序。
Session methods
Session session = subject.getSession();
Cryptography
密码学是隐藏或混淆数据的过程,因此窥探者无法理解它。Shiro 在密码学方面的目标是简化 JDK 的密码学支持并使之可用。重要的是要注意,密码学通常不是特定于主题的,因此它是 Shiro 的 API 的一个领域,它不是特定于主题的。您可以在任何地方使用 Shiro 的密码学支持,即使没有使用主题。Shiro 真正关注其密码学支持的两个领域是cryptographic hashes (也称为消息摘要) and cryptographic ciphers。
如果您使用过 JDK 的MessageDigest类,您很快就会意识到使用它有点麻烦。它有一个笨拙的基于工厂的静态方法 API 而不是面向对象的 API,并且您被迫捕获可能永远不需要捕获的已检查异常。如果您需要对消息摘要输出进行 hex-encode 或 Base64-encode,则只能靠您自己 - 两者都没有标准的 JDK 支持。Shiro 以简洁直观的哈希 API 解决了这些问题。
例如,让我们考虑一个相对常见的 MD5 散列文件并确定该散列值的十六进制值的情况。称为“checksum”,在提供文件下载时经常使用 - 用户可以对下载的文件执行自己的 MD5 哈希,并断言他们的校验和与下载站点上的校验和匹配。如果它们匹配,则用户可以充分假设文件在传输过程中没有被篡改。
以下是在没有Shiro的情况下您可以尝试执行此操作的方法:
1.将文件转换为字节数组。JDK 中没有任何东西可以帮助解决这个问题,因此您需要创建一个辅助方法来打开FileInputStream、使用字节缓冲区(byte buffer)并抛出适当的 IOExceptions 等。
2.使用MessageDigest类对字节数组进行散列处理,处理适当的异常,如下面的清单所示。
3.将散列字节数组编码为十六进制字符。JDK 中也没有任何东西可以帮助解决这个问题,因此您需要创建另一个辅助方法,并且可能在您的实现中使用按位运算和位移。
JDK 的 MessageDigest
Try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.digest(字节);
byte[] hashed = md.digest();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
对于如此简单且相对常见的事情,这是大量的工作。现在这里是如何用Shiro做同样的事情。
String hex = new Md5Hash(myFile).toHex();
当您使用 Shiro 来简化所有这些工作时,会变得非常简单和容易理解正在发生的事情。密码的 SHA-512 散列和 Base64 编码同样简单。
String encodedPassword =
new Sha512Hash(password, salt, count).toBase64();
您可以看到 Shiro 在多大程度上简化了散列和编码,在此过程中为您节省了一些理智。
Ciphers
密码是可以使用密钥可逆地转换数据的加密算法。我们使用它们来保证数据的安全,尤其是在传输或存储数据时,尤其是在数据特别容易被窥探的时候。
如果您曾经使用过 JDK Cryptography API,尤其是 javax.crypto.Cipher 类,您就会知道它是一个非常复杂的难以驯服的野兽。对于初学者来说,每个可能的 Cipher 配置总是由 javax.crypto.Cipher 的实例表示。是否需要做公钥/私钥加密吗?使用密码的时候是否需要使用分组密码进行流式操作?使用密码的时候需要创建 AES 256 位密码来保护数据?
以及如何创建所需的 Cipher 实例?您创建一个复杂的、不直观的以令牌分隔的密码选项字符串,称为“转换字符串”,然后将此字符串传递给 Cipher.getInstance 静态工厂方法。使用这种密码选项字符串方法,没有类型安全来确保您使用有效的选项。这也隐含地意味着没有 JavaDoc 可以帮助您理解相关选项。并且您还需要处理已检查的异常,以防您的 String 公式不正确,即使您知道配置是正确的。如您所见,使用 JDK 密码是一项相当繁琐的任务。这些技术在很久以前曾经是 Java API 的标准,但时代变了,我们想要一种更简单的方法。
Shiro 试图通过引入其 CipherService API 来简化密码学的整个概念。CipherService 是大多数开发人员在保护数据时想要的:一个简单的、无状态的、线程安全的 API,可以在一个方法调用中对整个数据进行加密或解密。您需要做的就是提供您的密钥,您可以根据需要进行加密或解密。例如,可以使用 256 位 AES 加密,如下面的清单所示。
Apache Shiro 的加密 API
AesCipherService cipherService = new AesCipherService();
cipherService.setKeySize(256);
//创建一个测试密钥:
byte[] testKey = cipherService.generateNewKey();
//加密文件的字节:
byte[] encrypted =
cipherService.encrypt(fileBytes, testKey);
与 JDK 的 Cipher API 相比,Shiro 示例更简单:
您可以直接实例化 CipherService - 没有奇怪或令人困惑的工厂方法。
密码配置选项表示为与 JavaBeans 兼容的 getter 和 setter——没有奇怪且难以理解的“转换字符串”。
加密和解密在单个方法调用中执行。
没有强制检查异常。如果你愿意,可以捕捉 Shiro 的 CryptoException。
Shiro 的 CipherService API 还有其他好处,例如支持基于字节数组的加密/解密(称为“块”操作)以及基于流的加密/解密(例如,加密音频或视频)。
Java Cryptography 不需要很痛苦。Shiro 的密码学支持旨在简化您保护数据安全的工作。
Web Support
最后但同样重要的是,我们将简要介绍 Shiro 的 Web 支持。Shiro 附带了一个强大的 Web 支持模块来帮助保护 Web 应用程序。为 Web 应用程序设置 Shiro 很简单。唯一需要的是在 web.xml 中定义一个 Shiro Servlet 过滤器。以下 显示了此代码。
ShiroFilter in web.xml
<filter>
<filter-name>ShiroFilter</filter-name>
<filter-class>
org.apache.shiro.web.servlet.IniShiroFilter
</filter-class>
<!-- no init-param means load the INI config
from classpath:shiro.ini -->
</filter>
<filter-mapping>
<filter-name>ShiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
此过滤器可以读取上述 shiro.ini 配置,因此无论部署环境如何,您都可以获得一致的配置体验。配置完成后,Shiro 过滤器将过滤每个请求,并确保在请求期间可以访问特定于请求的主题。由于它过滤每个请求,因此您可以执行特定于安全性的逻辑,以确保只允许满足特定条件的请求通过。
URL-Specific Filter Chains
Shiro 通过其创新的 URL 过滤器链接功能支持特定于安全的过滤器规则。它允许您为任何匹配的 URL 模式指定临时过滤器链。这意味着您在使用 Shiro 的过滤机制强制执行安全规则(或规则组合)方面具有很大的灵活性——比您单独在 web.xml 中定义过滤器要灵活得多。以下 显示了 Shiro INI 中的配置片段。
Listing . Path-specific Filter Chains
[urls]
/assets/** = anon
/user/signup = anon
/user/** = user
/rpc/rest/** = perms[rpc:invoke], authc
/** = authc
如您所见,Web 应用程序可以使用 [urls] INI 部分。对于每一行,等号左侧的值表示上下文相关的 Web 应用程序路径。右边的值定义了一个过滤器链——一个有序的、逗号分隔的 Servlet 过滤器列表,用于给定路径执行。每个过滤器都是一个普通的 Servlet 过滤器,但您在上面看到的过滤器名称(anon、user、perms、authc)是 Shiro 开箱即用的特殊安全相关过滤器。您可以混合和匹配这些安全过滤器,以创建非常自定义的安全体验。您还可以指定您可能拥有的任何其他现有 Servlet 过滤器。
这与使用 web.xml 相比要好多少,在 web.xml 中您定义一个过滤器块,然后定义一个单独的断开连接的过滤器模式块?使用 Shiro 的方法,更容易准确地查看为给定匹配路径执行的过滤器链。如果您愿意,您可以只在 web.xml 中定义 Shiro 过滤器,并在 shiro.ini 中定义所有其他过滤器和过滤器链,以获得比 web.xml 更简洁和易于理解的过滤器链定义机制。即使您没有使用 Shiro 的任何安全功能,仅这一点小便利就可以让 Shiro 值得使用。
JSP Tag Library
Shiro 还提供了一个 JSP 标记库,允许您根据当前 Subject 的状态控制 JSP 页面的输出。一个有用的常见示例是在用户登录后显示“Hello ”文本。但如果他们是匿名的,您可能想显示其他内容,例如“你好!今天报名!” 反而。清单 16 展示了如何使用 Shiro 的 JSP 标记来支持这一点。
Listing . JSP Taglib Example
<%@ taglib prefix="shiro"
uri="http://shiro.apache.org/tags" %>
...
<p>Hello
<shiro:user>
<!-- shiro:principal prints out the Subject’s main
principal - in this case, a username: -->
<shiro:principal/>!
</shiro:user>
<shiro:guest>
<!-- not logged in - considered a guest. Show
the register link: -->
! <a href=”register.jsp”>Register today!</a>
</shiro:guest>
</p>
还有其他标签允许您根据他们拥有(或不拥有)哪些角色、分配(或未分配)哪些权限以及它们是否经过身份验证、从“记住我”服务中记住或匿名客人。
Shiro 支持许多其他特定于 Web 的功能,例如简单的“记住我”服务、REST 和 BASIC 身份验证,当然还有透明的 HttpSession 支持(如果您想使用 Shiro 的本机企业会话)。有关更多信息,请参阅Apache Shiro 网络文档。
Web Session Management
Shiro 对 Web 环境中的会话的支持。
Default Http Sessions
对于 Web 应用程序,Shiro 默认其会话基础结构使用我们都习惯的现有 Servlet 容器会话。也就是说,当您调用方法 subject.getSession() 和 subject.getSession(boolean) 时,Shiro 将返回由 Servlet 容器的 HttpSession 实例支持的 Session 实例。这种方法的美妙之处在于,调用 subject.getSession() 的业务层代码与 Shiro Session 实例交互——它不知道它正在使用基于 Web 的 HttpSession 对象。在跨架构层保持干净分离时,这是一件非常好的事情。
Shiro’s Native Sessions in the Web Tier
如果您因为需要 Shiro 的企业会话功能(例如独立于容器的集群)而在 Web 应用程序中启用了 Shiro 的本机会话管理,那么您当然希望 HttpServletRequest.getSession() 和 HttpSession API 与“本机”会话和不是 servlet 容器会话。如果你不得不重构任何使用 HttpServletRequest 和 HttpSession API 的代码来代替使用 Shiro 的 Session API,那将是非常令人沮丧的。Shiro当然不会期望你这样做。相反,Shiro 完全实现了 Servlet 规范的 Session 部分,以支持 Web 应用程序中的本地会话。这意味着每当您调用相应的 HttpServletRequest 或 HttpSession 方法调用时,Shiro 都会将这些调用委托给其内部的原生 Session API。
Additional Features
Apache Shiro 框架中的其他功能对保护 Java 应用程序很有用,例如:
跨线程维护主题的线程和并发支持(Executor 和 ExecutorService 支持)
Callable 和 Runnable 支持将逻辑作为特定主题执行
“运行方式”支持假设另一个主题的身份(例如在管理应用程序中有用)
测试工具支持,使得在单元和集成测试中对 Shiro 安全代码进行全面测试变得非常容易。
Framework Limitations(框架限制)
正如我们所希望的那样,Apache Shiro 并不是一颗“灵丹妙药”——它不会毫不费力地解决所有安全问题。Shiro 没有解决的一些事情可能值得了解
Virtual Machine-level concerns(虚拟机级别的问题)
Apache Shiro 目前不处理虚拟机级别的安全性,例如基于访问控制策略防止某些类加载到类加载器中的能力。然而,Shiro 可以与现有的 JVM 安全操作集成并不是不可想象的——只是没有人为该项目贡献过这样的工作。
Multi-Stage Authentication(多阶段身份验证)
Shiro 目前不支持“多阶段”身份验证,用户可能通过一种机制登录,然后被要求使用不同的机制再次登录。这已经在基于 Shiro 的应用程序中完成,但是通过应用程序预先收集所有必需的信息,然后与 Shiro 交互。未来的 Shiro 版本很有可能支持此功能。
Realm Write Operations(Realm 写入操作):
目前所有 Realm 实现都支持“读取”操作,用于获取身份验证和授权数据以执行登录和访问控制。不支持“写入”操作,例如创建用户帐户、组和角色,或将用户与角色组和权限相关联。这是因为支持这些操作的数据模型因应用程序而异,并且很难对所有 Shiro 用户强制执行“写入”API。
它与 Spring Security 相比如何?
我对 Spring Security 的体验是,虽然它不依赖于在 Servlet/JSP 环境中运行,但在开发人员易于使用方面,它严重偏向于 Web 应用程序。换句话说,如果可以使用 XML 命名空间支持满足您的要求,再加上一些随处插入的自定义策略实现,那么 SS 将是一种愉快的体验。如果您必须自己连接基础架构级别的 bean,那么您正在从高级抽象到低级框架管道的剪切悬崖上掉下来。
我希望 Shiro 在其抽象方面更加平衡,无论运行时环境如何,无论是轻量级 Web、完整的 JEE/EJB、自定义客户端/服务器还是移动设备,都可以为开发人员提供相同级别的支持。
原文链接 -----https://www.infoq.com/articles/apache-shiro/
总结:看完原文对shrio的验证和授权有了初步了解,但只是知道一些概念。反问自己该如何实现还是一知半解,需要实践应用才能更好的了解。