英文官方文档
(我想看什么博客,也没有自己亲自去读读官方文档更好了。毕竟这样原滋原味)
本文是读 中文译文介绍 shiro 的笔记
Apache Shiro 是一个强大易用的 Java 安全框架,提供了认证、授权、加密和会话管理功能,可为任何应用提供安全保障 —— 从命令行应用、移动应用到大型网络及企业应用。
Shiro 为解决下列问题提供了保护应用的 API:
Shiro 还支持一些辅助特性,如 Web 应用安全、单元测试和多线程,它们的存在强化了上面提到的四个要素。
Subject,SecurityManager 和 Realms
shiro 基于当前 每个用户 考虑应用安全。
准确来说,“Subject” 仅仅意味着“当前跟软件交互的东西”;它可以是人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。但考虑到大多数目的和用途,你可以把 subject 认为是 Shiro 的“用户”概念。
import org.apache.shiro.subject.Subject;
import org.apache.shiro.SecurityUtils;
...
Subject currentUser = SecurityUtils.getSubject();
一旦获得 Subject,你就可以立即获得你希望用 Shiro 为当前用户做的 90% 的事情,如登录、登出、访问会话、执行授权检查等。
在代码的任何地方都能很轻松地访问 Subject,允许在任何需要的地方进行安全操作。
Subject 代表了当前用户的安全操作,SecurityManager 则管理所有用户的安全操作。
SecurityManager 是 Shiro 框架的核心,引用多个内部嵌套安全组件,它们形成了对象图。但是,一旦 SecurityManager 及其内部对象图配置好,它就会退居幕后,应用开发人员几乎把他们的所有时间都花在 Subject API 调用上。
一个应用几乎总是只有一个 SecurityManager 实例。它实际是应用的 Singleton(尽管不必是一个静态Singleton)—— 单例模式。
Realm 是 shiro 与 安全的应用数据的“ 桥 ”,将二者连接起来。
举个例子:切实与用户账户这类安全应用数据交互时,执行认证(登录)和授权(访问控制)时,Shiro 会从应用配置的 Realm 中查找很多内容。
从这个意义上讲,Realm 实质上是一个安全相关的 DAO :它封装了数据源的连接细节,并在需要时将相关数据提供给 Shiro。当配置 Shiro 时,你必须至少指定一个 Realm,用于认证和(或)授权。配置多个 Realm 是可以的。
Shiro 以简单直观的方式支持同样的流程。几乎你想要用 Shiro 在运行时完成的所有事情都能通过与当前执行的 Subject 进行交互而达成(Shiro 有一个以 Subject 为中心的 API)。
因此,要登录 Subject,只需要调用它的 login 方法,传入表示被提交当事人和证书(在这种情况下,就是用户名和密码)的 AuthenticationToken 实例。
//1. 接受提交的当事人和证书:
AuthenticationToken token =
new UsernamePasswordToken(username, password);
//2. 获取当前 Subject:
Subject currentUser = SecurityUtils.getSubject();
//3. 登录:
currentUser.login(token);
在调用了 login 方法后,SecurityManager 会收到 AuthenticationToken,并将其发送给已配置的 Realm,执行必须的认证检查。
每个 Realm 都能在必要时对提交的 AuthenticationTokens 作出反应。如果认证(登录)失败,可以进行相应地反映:
//1. 接受提交的当事人和证书:
AuthenticationToken token =
new UsernamePasswordToken(username, password);
//2. 获取当前 Subject:
Subject currentUser = SecurityUtils.getSubject();
//3. 登录:
try {
currentUser.login(token);
} catch (IncorrectCredentialsException ice) {
…
} catch (LockedAccountException lae) {
…
} catch (AuthenticationException ae) {…
}
Subject 登录成功后,他们就被认为是已认证的,通常你会允许他们使用你的应用。但是,他们只能做被 授权 的事。
授权实质上就是访问控制 —— 控制用户能够访问应用中的哪些内容。
多通过使用诸如角色和权限这类概念完成的。也就是说,通常用户允许或不允许做的事情是根据分配给他们的角色或权限决定的。
如你期望的,Subject API 让你可以很容易的执行角色和权限检查。
if ( subject.hasRole(“administrator”) ) {
// 显示‘Create User’按钮
} else {
// 按钮置灰?
}
角色检查有个很大的缺陷:你无法在运行时增删角色。
角色名字在这里是硬编码,所以,如果你修改了角色名字或配置,你的代码就会乱套!如果你需要在运行时改变角色含义,或想要增删角色,你必须另辟蹊径 —— 权限检查。
if ( subject.isPermitted(“user:create”) ) {
// 显示‘Create User’按钮
} else {
// 按钮置灰?
}
任何具有“user:create”权限的角色或用户都可以点击‘Create User’按钮,并且这些角色和指派甚至可以在运行时改变,这给你提供了一个非常灵活的安全模型。
在安全框架领域,Apache Shiro 提供了一些独特的东西:可在任何应用或架构层一致地使用 Session API。
Shiro 会话的一好处就是,如果需要,会话数据可以跨客户端技术进行共享。例如,Swing 桌面客户端在需要时可以参与相同的 Web 应用会话中 - 如果最终用户同时使用这两种应用,这样的功能会很有用。那你如何在任何环境中访问 Subject 的会话呢?请看下面的示例,里面使用了 Subject 的两个方法。
在加密方面,Shiro 的目标是简化并让 JDK 的加密支持可用。
清楚一点很重要:一般情况下,加密不是特定于 Subject 的,加密是 Shiro API 的一部分。你可以在任何地方使用 Shiro 的加密支持,甚至在不使用 Subject 的情况下。
对于加密支持,Shiro 真正关注的两个领域是加密哈希(又名消息摘要)和加密密码。
JDK 的消息摘要
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.digest(bytes);
byte[] hashed = md.digest();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
Shiro 的消息摘要
String hex = new Md5Hash(myFile).toHex();
最后,但并非不重要,我们将简单介绍一下 Shiro 的 Web 支持。Shiro 附带了一个帮助保护 Web 应用的强建的 Web 支持模块。对于 Web 应用,安装 Shiro 很简单。唯一需要做的就是在 web.xml 中定义一个 Shiro Servlet 过滤器。清单 14 中,列出了代码。
<filter>
<filter-name>ShiroFilterfilter-name>
<filter-class>
org.apache.shiro.web.servlet.IniShiroFilter
filter-class>
filter>
<filter-mapping>
<filter-name>ShiroFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
这个过滤器可以读取上述 shiro.ini 配置,这样不论什么开发环境,你都拥有了一致的配置体验。一旦完成配置,Shiro Filter 就会过滤每个请求并且确保在请求期间特定请求的 Subject 是可访问的。同时由于它过滤了每个请求,你可以执行安全特定的逻辑以保证只有满足一定标准的请求才被允许通过。
Shiro 通过其创新的 URL 过滤器链功能支持安全特定的过滤规则。它允许你为任何匹配的 URL 模式指定非正式的过滤器链。这意味着, 使用 Shiro 的过滤器机制,你可以很灵活的强制安全规则(或者规则的组合) - 其程度远远超过你单独在 web.xml 中定义过滤器时所获得的。清单 15 中显示了 Shiro INI 中的配置片段。
[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,在其中先定义过滤器块,然后定义单独分离的过滤器模式块,这种方式带来的好处有多少?采用 Shiro 的方法,可以很容易就准确知道针对给定匹配路径执行的过滤器链。如果想这么做,你可以在 web.xml 中仅定义 Shiro Filter,在 shiro.ini 中定义所有其他的过滤器和过滤器链,这要比 web.xml 简洁得多,而且更容易理解过滤器链定义机制。即使不使用 Shiro 的任何安全特性,单凭这样小小的方便之处,也值得让你使用 Shiro。
最后值得一提的是 Shiro 在 Web 环境中对会话的支持。
对于 Web 应用,Shiro 缺省将使用我们习以为常的 Servlet 容器会话作为其会话基础设施。即,当你调用 subject.getSession() 和 subject.getSession(boolean) 方法时,Shiro 会返回 Servlet 容器的 HttpSession 实例支持的 Session 实例。这种方式的曼妙之处在于调用 subject.getSession() 的业务层代码会跟一个 Shiro Session 实例交互 - 还没有“认识”到它正跟一个基于 Web 的 HttpSession 打交道。这在维护架构层之间的清晰隔离时,是一件非常好的事情。
如果你由于需要 Shiro 的企业级会话特性(如容器无关的集群)而打开了 Shiro 的原生会话管理,你当然希望 HttpServletRequest.getSession() 和 HttpSession API 能和“原生”会话协作,而非 Servlet 容器会话。如果你不得不重构所有使用 HttpServletRequest 和 HttpSession API 的代码,使用 Shiro 的 Session API 来替换,这将非常令人沮丧。Shiro 当然从来不会期望你这么做。相反,Shiro 完整实现了 Servlet 规范中的 Session 部分以在 Web 应用中支持原生会话。这意味着,不管何时你使用相应的 HttpServletRequest 或 HttpSession 方法调用,Shiro 都会将这些调用委托给内部的原生会话 API。结果,你无需修改 Web 代码,即便是你正在使用 Shiro 的‘原生’企业会话管理 - 确实是一个非常方便(且必要)的特性。
本文在很大程度上,引用原文内容。摘录作者认为自己应该知道的一些内容。