shiro实战系列(十)之Subject

毫无疑问,在 Apache Shiro 中最重要的概念就是 Subject。‘Subject‘仅仅是一个安全术语,是指应用程序用户的特定 安全的“视图”。一个 Shiro Subject 实例代表了一个单一应用程序用户的安全状态和操作。

这些操作包括:

authentication(login)

authorization(access control)

session access

logout

我们原本希望把它称为"User"由于这样“很有意义”,但是我们决定不这样做:太多的应用程序现有的 API 已经有 自己的 User classes/frameworks,我们不希望和这些起冲突。此外,在安全领域,"Subject"这一词实际上是公认的术 语。

Shiro 的 API 为应用程序提供 Subject 为中心的编程范式支持。当编码应用程序逻辑时,大多数应用程序开发人员想 知道谁才是当前正在执行的用户。虽然应用程序通常能够通过它们自己的机制(UserService 等)来查找任何用户, 但涉及到安全性时,最重要的问题是“谁才是当前的用户?”。

虽然通过使用SecurityManager可以捕获任何Subject,但只有基于当前用户/Subject的应用程序代码更自然,更直观。

The Currently Executing Subject(当前执行的 Subject)

几乎在所有环境下,你能够获得当前执行的 Subject 通过使用 org.apache.shiro.SecurityUtils:

getSubject()方法调用一个独立的应用程序,该应用程序可以返回一个在应用程序特有位置上基于用户数据的 Subject, 在服务器环境中(如,Web 应用程序),它基于与当前线程或传入的请求相关的用户数据上获得 Subject。

当你获得了当前的 Subject 后,你能够拿它做些什么?

如果你想在他们当前的 session 中使事情对用户变得可用,你可得的他们的 session:

Session 是一个 Shiro 的具体实例,它提供了大多数你经常要和 HttpSessions 用到的东西,但有一些额外的好处和一 个很大的区别:它不需要一个 HTTP 环境!   如果在 Web 应用程序内部部署,默认的 Session 将会是基于 HttpSession 的。但是,在一个非 Web 环境中,像这个 简单的 Quickstart,Shiro 将会默认自动地使用它的 Enterprise Session Management。这意味着你可以在你的应用程序 中使用相同的 API,在任何层,无论部署环境。这打开了应用程序的全新世界,由于任何需要 session 的应用程序不 再被强迫使用 HttpSession 或 EJB Stateful Session Beans。而且,任何客户端技术现在能够共享会话数据。   所以,你现在可以获取一个 Subject 以及他们的 Session。对于真正有用的东西像检查会怎么样呢,如果他们被允许 做某些事——如对角色和权限的检查?   嗯,我只能对已知的用户做这些检查。我们的 Subject 实例代表了当前的用户,但谁又是实际上的当前用户呢?呃, 他们都是匿名的——也就是说,直到他们至少登录一次。那么,让我们像下面这样做:

那就是了!它再简单不过了。   但如果他们的登录尝试失败了会怎么样?你可以捕获各种各样的具体的异常来告诉你到底发生了什么:

你,作为应用程序/GUI 开发人员,可以基于异常选择是否显示消息给终端用户(例如,“在系统中没有与该用户名 对应的帐户。”)。有许多不同种类的异常供你检查,或者你可以抛出你自己自定义的异常,这些异常可能是 Shiro 还未提供的。有关详情,请查看 AuthenticationException 的 JavaDoc。   好了,现在,我们有了一个登录的用户,我们还有什么可以做的呢?   比方说,他们是谁:

最后,当用户完成了对应用程序的使用时,他们可以注销:

这个简单的 API 包含了 90%的 Shiro 终端用户在使用 Shiro 时将会处理的东西。

Custom Subject Instances(自定义 Subject 实例) Shiro 1.0 中添加了一个新特性,能够在特殊情况下构造自定义/临时的 subject 实例。

Special Use Only!  你应该总是通过调用 SubjectUtils.getSubject()来获得当前正在执行的 Subject;  创建自定义的 Subject 实例只应在特殊情况下进行。

当一些“特殊情况”是,这是可以很有用的: 系统启动/引导——当没有用户月系统交互时,代码应该作为一个‘system‘或 daemon 用户来执行。创建 Subject 实例来代表一个特定的用户是值得的,这样引导代码能够以该用户(如 admin)来执行。 鼓励这种做法是由于它能保证 utility/system 代码作为一个普通用户以同样的方式执行,以确保代码是一致的。 这使得代码更易于维护,因为你不必担心 system/daemon 方案的自定义代码块。 集成测试——你可能想创建Subject实例,在必要时可以在集成测试中使用。请参阅测试文档获取更多的内容。 Daemon/background 进程的工作——当一个 daemon 或 background 进程执行时,它可能需要作为一个特定的 用户来执行。

好了,假设你仍然需要创建自定义的 Subject 实例的情况下,让我们看看如何来做:

Subject.Builder

Subject.Builder 被制定得非常容易创建 Subject 实例,而无需知道构造细节。   Builder 最简单的用法是构造一个匿名的,session-less 的实例。

上面所展示的默认的 Subject.Builder 无参构造函数将通过 SecurityUtils.getSubject()方法使用应用程序当前可访问的 SecurityManager。你也可以指定被额外的构造函数使用的 SecurityManager 实例,如果你需要的话:

所有其他的 Subject.Builder 方法可以在 buildSubject()方法之前被调用,它们来提供关于如何构造 Subject 实例的上下 文。例如,假如你拥有一个 session ID ,想取得“拥有”该 session 的 Subject(假设该 session 存在且未过期):

同样地,如你想创建一个 Subject 实例来反映一个确定的身份:

然后,你可以使用构造的 Subject 实例,如预期一样对它进行调用。但请注意:   构造的 Subject 实例不会由于应用程序(线程)的进一步使用而自动地绑定到应用程序(线程)。如果你想让它对 于任何代码都能够方便地调用 SecurityUtils.getSubject(),你必须确保创建好的 Subject 有一个线程与之关联。

Thread Association(线程关联) 如上所述,只是构建一个 Subject 实例,并不与一个线程相关联——一个普通的必要条件是在线程执行期间任何对 SecurityUtils.getSubject()的调用是否能正常工作。确保一个线程与一个 Subject 关联有三种途径:

(1) Automatic Association(自动关联)—— 通过 Sujbect.execute*方法执行一个 Callable 或 Runnable 方法会自动地绑 定和解除绑定到线程的 Subject,在 Callable/Runnable 异常的前后。

(2) Manual Association(手动关联)——你可以在当前执行的线程中手动地对 Subject 实例进行绑定和解除绑定。这 通常对框架开发人员非常有用。

(3) Different Thread(不同的线程)——通过调用 Subject.associateWith*方法将 Callable 或 Runnable 方法关联到 Subject,然后返回的 Callable/Runnable 方法在另一个线程中被执行。如果你需要为 Subject 在另一个线程上执 行工作的话,这是首选的方法。

了解线程关联最重要的是,两件事情必须始终发生:

1. Subject 绑定到线程,所以它在线程的所有执行点都是可用的。Shiro 做到这点通过它的 ThreadState 机制,该 机制是在 ThreadLocal 上的一个抽象。

2. Subject 将在某点解除绑定,即使线程的执行结果是错误的。这将确保线程保持干净,并在 pooled/reusable 线 程环境中清除任何之前的 Subject 状态。   这些原则保证在上述三个机制中发生。接下来阐述它们的用法。

Automatic Association(自动关联)

如果你只需要一个 Subject 暂时与当前的线程相关联,同时你希望线程绑定和清理自动发生,Subject 的 Callable 或 Runnable 的直接执行正是你所需要的。在 Subject.execute 调用返回后,当前线程被保证当前状态与执行前的状态是 一样的。这个机制是这三个中使用最广泛的。

例如,让我们假定你有一些逻辑在系统启动时需要执行。你希望作为一个特定用户执行代码块,但一旦逻辑完成后, 你想确保线程/环境自动地恢复到正常。你可以通过调用 Subject.execute*方法来做到:

这种方法在框架开发中也是很有用的。例如,Shiro 对 secure Spring remoting 的支持确保了远程调用能够作为一个特 定的 Subject 来执行:

Manual Association(手动关联)

虽然 Subject.execute*方法能够在它们返回后自动地清理线程的状态,但有可能在一些情况下,你想自己管理 ThreadState。当结合 w/Shiro 时,这几乎总是在框架开发层次使用,但它很少在 bootstrap/daemon 情景下使用(上 面 Subject.execute(callable)例子使用得更为频繁)。

最好的做法是在 try/finally 块保证清理:

有趣的是,这正是 Subject.execute*方法实际上所做的——它们只是在 Callable 或 Runnable 执行前后自动地执行这个 逻辑。Shiro 的 ShiroFilter 为 Web 应用程序执行几乎相同的逻辑(ShiroFilter 使用 Web 特定的 ThreadState 的实现, 超出了本节的范围)。

A Different Thread

如果你有一个 Callable 或 Runnable 实例要以 Subject 来执行,你将自己执行 Callable 或 Runnable(或这将它移交给 线程池或执行者或 ExcutorService),你应该使用 Subject.associateWith*方法。这些方法确保在最终执行的线程中保 留 Subject,且该 Subject 是可访问的。

原文地址:https://www.cnblogs.com/youcong/p/9185874.html

时间: 2024-08-30 07:02:16

shiro实战系列(十)之Subject的相关文章

shiro实战系列(十二)之常用专业术语

请花 2 分钟来阅读和理解它--这很重要.真的.这里的术语和概念在文档的任何地方都被涉及到,它将在总体上 大大简化你对 Shiro 和安全的理解.   由于所使用的术语使得安全可能令人困惑.我们将通过澄清一些核心概念使生活更容易,你将会看到 Shiro API 是如 何很好地反映了它们: (1)Authentication 身份验证是验证 Subject 身份的过程--实质上是证明某些人是否真的是他们所说的他们是谁.当认证尝试成 功后,应用程序能够相信该 subject 被保证是其所期望的.  

shiro实战系列(十五)之Spring集成Shiro

Shiro 的 JavaBean 兼容性使得它非常适合通过 Spring XML 或其他基于 Spring 的配置机制.Shiro 应用程序需要一个具 有单例 SecurityManager 实例的应用程序.请注意,这不会是一个静态的单例,但应该只有一个应用程序能够使用 的实例,无论它是否是静态单例的. Web Applications Shiro 拥有对 Spring Web 应用程序的一流支持.在 Web 应用程序中,所有 Shiro 可访问的万恶不请求必须通过一个 主要的 Shiro 过滤

shiro实战系列(六)之Authorization(授权)

授权,又称作为访问控制,是对资源的访问管理的过程.换句话说,控制谁有权限在应用程序中做什么. 授权检查的例子是:该用户是否被允许访问这个网页,编辑此数据,查看此按钮,或打印到这台打印机?这些都是 决定哪些是用户能够访问的. 授权的要素: Apache Shiro 中的权限代表着安全政策中最基础的元素.它们从根本上作出了对行为的声明,并明确表示可以在应用程序中做什么.一个格式良好的权限声明基本上描述了资源以及当 Subject 与这些资源进行交互时可能出现的行 为. 权限语句的一些例子: ?(1)

MP实战系列(十二)之封装方法详解(续二)

继续MP实战系列(十一)之封装方法详解(续一)这篇文章之后. 此次要讲的是关于查询. 查询是用的比较多的,查询很重要,好的查询,加上索引如鱼得水,不好的查询加再多索引也是无济于事. 1.selectById()方法 演示示例: UserEntity user = ud.selectById(33); System.out.println(user.getEmail()); 简单的说明: 如果是在MyBatis中,需要再对应的xml编写这样的sql select column1,column2..

shiro实战系列(三)之架构

Apache Shiro 的设计目标是通过直观和易于使用来简化应用程序安全.Shiro 的核心设计体现了大多数人们是如何考虑应用程序安全的--在某些人(或某些事)与应用程序交互的背景下.   应用软件通常是基于用户背景情况设计的.也就是说,你将经常设计用户接口或服务 API,基于一个用户将要(或 应该)如何与该软件交互.例如,你可能会说,"如果用户与我的应用程序交互的用户已经登录,我将显示一个他 们能够点击的按钮来查看他们的帐户信息.如果他们没有登录,我将显示一个登录按钮."   这个

shiro实战系列(四)之配置

Shiro之配置 Shiro 被设计成能够在任何环境下工作,从最简单的命令行应用程序到最大的的企业群集应用.由于环境的多样性,使得许多配置机制适用于它的配置. 一. 许多配置选项 Shiro的SecurityManager实现及所支持的组件都是兼容JavaBean的.这使得Shiro几乎能使用任何配置格式,如regular Java,XML(Spring, JBoss, Guice,等等),YAML,JSON,Groovy Builder markup,以及更多的配置. 二. 可编程配置 创建一

openstack运维实战系列(十二)之nova aggregate资源分组

1. 背景说明    openstack设计时的宗旨是能够为企业提供大规模的云计算服务,包括计算,存储,网络等资源,以服务的形式交付给用户,在一个非常大的环境中,需要将openstack的资源划分,openstack nova支持三种划分的方式:Region区域,Zone空间和Aggregate分组,其中Region是指一个地区或者地域,如可以将中国划分为:华南地区,华中地区,东北地区,西南地区:Zone则可以按照机房的形式来划分,如北京兆维机房为一个Zone,北京鲁谷机房为另外一个Zone:A

openstack运维实战系列(十八)nova与ceph结合

1. 背景说明    nova负责虚拟机的生命周期管理,包括创建,删除,重建,开机,关机,重启,快照等,作为openstack的核心,nova负责IaaS中计算重要的职责,其中nova的存储格外重要,默认情况下,nova将instance的数据存放在/var/lib/nova/instances/%UUID目录下,使用本地的存储空间.使用这种方式带来的好处是:简单,易实现,速度快,故障域在一个可控制的范围内.然而,缺点也非常明显:compute出故障,上面的虚拟机down机时间长,没法快速恢复,

MP实战系列(九)之集成Shiro

下面示例是在之前的基础上进行的,大家如果有什么不明白的可以参考MP实战系列的前八章 当然,同时也可以参考MyBatis Plus官方教程 建议如果参考如下教程,使用的技术为spring+mybatis plus + springmvc+jdk8+maven工程 满足这个条件可以减少不必要的麻烦,当然持久层也可以用mybatis. 只要按照如下示例来,也不会有大问题的.之前我也强调过mybatis和mybatis plus的区别主要是封装和继承,mybatis plus封装一系列增删改查的方法,但