Shiro 中的 SecurityUtils(转)
在 Shiro 中 SecurityUtils
是一个抽象类。并且没有任何子类。在其中声明了一个静态属性,三个静态方法。
静态属性 securityManager
private static SecurityManager securityManager;
用来存储当前应用中全局唯一的一个SecurityManager。
有两个静态方法是为此静态属性服务器,也就是下面这两个:
public static void setSecurityManager(SecurityManager securityManager) {
SecurityUtils.securityManager = securityManager;
}
public static SecurityManager getSecurityManager() throws UnavailableSecurityManagerException {
SecurityManager securityManager = ThreadContext.getSecurityManager();
if (securityManager == null) {
securityManager = SecurityUtils.securityManager;
}
if (securityManager == null) {
String msg = "No SecurityManager accessible to the calling code, either bound to the " +
ThreadContext.class.getName() + " or as a vm static singleton. This is an invalid application " +
"configuration.";
throw new UnavailableSecurityManagerException(msg);
}
return securityManager;
}
getSubject 静态方法
这个是 Shiro 中最核心的方法了,用来获取 Subject.
public static Subject getSubject() {
Subject subject = ThreadContext.getSubject();
if (subject == null) {
subject = (new Subject.Builder()).buildSubject();
ThreadContext.bind(subject);
}
return subject;
}
上述方法中,第二行(Subject subject = ThreadContext.getSubject();
)获取到的Subject其实是第五行(ThreadContext.bind(subject);
)绑定的。
如果没有之前的绑定则得到null
,然后就会走第四行(subject = (new Subject.Builder()).buildSubject();
)获取。步骤如下:
- 调用Subject.Builder类的无参构造方法。如下代码:
public Builder() {
this(SecurityUtils.getSecurityManager());
}
在这个无参构造方法中,以当前应用全局唯一的SecurityManager
对象为参调用了构造方法。如下:
public Builder(SecurityManager securityManager) {
if (securityManager == null) {
throw new NullPointerException("SecurityManager method argument cannot be null.");
}
this.securityManager = securityManager;
this.subjectContext = newSubjectContextInstance();
if (this.subjectContext == null) {
throw new IllegalStateException("Subject instance returned from 'newSubjectContextInstance' " +
"cannot be null.");
}
this.subjectContext.setSecurityManager(securityManager);
}
其实这些都不重要,至此我们知道了 Subject.Builder
对象中的SecurityManager
对象,其实就是当前应用全局唯一的SecurityManager
对象。
注:以后在Shiro中,只要看到SecurityManager
对象,你就认为它是当前应用全局唯一的那个SecurityManager
对象就行了。
- 调用
Subject.Builder
对象的buildSubject
方法。
public Subject buildSubject() {
return this.securityManager.createSubject(this.subjectContext);
}
其实里面是调用了SecurityManager
对象的createSubject
方法的,至于那个subjectContext
参数,我们可以暂时不用理会。(在不同的应用环境下subjectContext
是不一样的,如Web环境下它默认是DefaultWebSubjectContext
)
// DefaultSecurityManager 中的 createSubject 方法
public Subject createSubject(SubjectContext subjectContext) {
//create a copy so we don't modify the argument's backing map:
SubjectContext context = copy(subjectContext);
//ensure that the context has a SecurityManager instance, and if not, add one:
context = ensureSecurityManager(context);
//Resolve an associated Session (usually based on a referenced session ID), and place it in the context before
//sending to the SubjectFactory. The SubjectFactory should not need to know how to acquire sessions as the
//process is often environment specific - better to shield the SF from these details:
context = resolveSession(context);
//Similarly, the SubjectFactory should not require any concept of RememberMe - translate that here first
//if possible before handing off to the SubjectFactory:
context = resolvePrincipals(context);
Subject subject = doCreateSubject(context);
//save this subject for future reference if necessary:
//(this is needed here in case rememberMe principals were resolved and they need to be stored in the
//session, so we don't constantly rehydrate the rememberMe PrincipalCollection on every operation).
//Added in 1.2:
save(subject);
return subject;
}
复制SubjectContext
对象之后执行的 context = ensureSecurityManager(context);
是为了确保在SubjectContext
对象中已经注入了当前应该用全局唯一的SecurityManager
对象:
// DefaultSecurityManager 中的 ensureSecurityManager 方法
protected SubjectContext ensureSecurityManager(SubjectContext context) {
if (context.resolveSecurityManager() != null) {
log.trace("Context already contains a SecurityManager instance. Returning.");
return context;
}
log.trace("No SecurityManager found in context. Adding self reference.");
context.setSecurityManager(this);
return context;
}
也就是说,在SubjectContext
中的SecurityManager
也正是当前应该用全局唯一的SecurityManager
对象。
由createSubject
方法可知,在创建 Subject
前完成了以下两步工作:
- 解析了
Session
(context = resolveSession(context);
); - 解析了
Principals
(context = resolvePrincipals(context);
)。
创建Subject
之后,又执行了save(subject);
。如果继续扒代码你会发现,这一步其实是把Subject
存储到了Session
中。具体代码如下所示:
// DefaultSecurityManager 中的 save 方法
protected void save(Subject subject) {
this.subjectDAO.save(subject);
}
// SubjectDAO 接口的默认实现类 DefaultSubjectDAO 中的 save 方法
public Subject save(Subject subject) {
if (isSessionStorageEnabled(subject)) {
saveToSession(subject);
} else {
log.trace("Session storage of subject state for Subject [{}] has been disabled: identity and " +
"authentication state are expected to be initialized on every request or invocation.", subject);
}
return subject;
}
// SubjectDAO 接口的默认实现类 DefaultSubjectDAO 中的 saveToSession方法
protected void saveToSession(Subject subject) {
//performs merge logic, only updating the Subject's session if it does not match the current state:
mergePrincipals(subject);
mergeAuthenticationState(subject);
}
作者:JSON_NULL
链接:https://www.jianshu.com/p/cf95e3468638
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Shiro 中的 SecurityUtils(转)的更多相关文章
- Shiro中的授权问题(二)
上篇博客(Shiro中的授权问题 )我们介绍了Shiro中最最基本的授权问题,以及常见的权限字符的匹配问题.但是这里边还有许多细节需要我们继续介绍,本节我们就来看看Shiro中授权的一些细节问题. 验 ...
- Shiro中的授权问题
在初识Shiro一文中,我们对Shiro的基本使用已经做了简单的介绍,不懂的小伙伴们可以先阅读上文,今天我们就来看看Shiro中的授权问题. Shiro中的授权,大体上可以分为两大类,一类是隐式角色, ...
- Shiro中的Rememberme后出现浏览器500错误
问题详述:在Shiro中添加Remember me功能后,只要勾选Remember me选项为true的时候,浏览器就会跳转到一个不可达页面,并且在Chrome中显示HTTP 500错误. 问题追踪: ...
- Shiro中Realm
6.1 Realm [2.5 Realm]及[3.5 Authorizer]部分都已经详细介绍过Realm了,接下来再来看一下一般真实环境下的Realm如何实现. 1.定义实体及关系 即用户-角色 ...
- shiro中INI配置
4.1 根对象SecurityManager 从之前的Shiro架构图可以看出,Shiro是从根对象SecurityManager进行身份验证和授权的:也就是所有操作都是自它开始的,这个对象是线程安全 ...
- 项目一:第十三天 1、菜单数据管理 2、权限数据管理 3、角色数据管理 4、用户数据管理 5、在realm中动态查询用户权限,角色 6、Shiro中整合ehcache缓存权限数据
1 课程计划 菜单数据管理 权限数据管理 角色数据管理 用户数据管理 在realm中动态查询用户权限,角色 Shiro中整合ehcache缓存权限数据 2 菜单数据添加 2.1 使用c ...
- shiro中接入单点登录功能
最近新建的系统中使用了shiro,而shiro框架中包含登录认证和鉴权的功能,因为我们系统要统一接入公司内部的单点登录(isso)系统,所以通过isso的登录用户,需要在shiro中置为已认证,一下提 ...
- Shiro中Subject对象的创建与绑定流程分析
我们在平常使用Shrio进行身份认证时,经常通过获取Subject 对象中保存的Session.Principal等信息,来获取认证用户的信息,也就是说Shiro会把认证后的用户信息保存在Subjec ...
- 从零到实现Shiro中Authorization和Authentication的缓存
本文大纲 一.简介 二.缓存的概念 三.自定义实现缓存机制 四.什么是Ehcache 五.Ehcache怎么用 六.Spring对缓存的支持 七.Spring+Ehcache实现 八.Spring+S ...
随机推荐
- java读写cookie中文乱码解决方法
1.写入的时候: public boolean addCookie( HttpServletRequest req, HttpServletResponse resp){ //创建 Cookie co ...
- go 包的概念
------------------------------------------------------------------ package main import ( "fmt&q ...
- linux 安装xdebug
一.安装了 xdebug php -m | grep 'xdebug' 如果没有安装就执行 首先根据 phpinfo() 信息 下载对应的版本,具体看参数: 下载地址:https://xdebug.o ...
- 少儿编程Scratch第四讲:射击游戏的制作,克隆的奥秘
上周的宇宙大战射击游戏中,我们只完成了宇宙飞船发射子弹的部分.还未制作敌对方.这周制作了敌方-飞龙,飞龙随机在屏幕上方出现,如果被子弹打中,则得分,飞龙和子弹都消失. 敌方:飞龙:计分. 目的 目的: ...
- Arm-Linux 移植 QT5.9 带 tslib,QT-creator配置
平台 : Ubuntu 16.04 QT :5.9.8 tslib : 1.4arm-gcc ...
- 将迁移学习用于文本分类 《 Universal Language Model Fine-tuning for Text Classification》
将迁移学习用于文本分类 < Universal Language Model Fine-tuning for Text Classification> 2018-07-27 20:07:4 ...
- 写文章 通俗易懂 悲观锁、乐观锁、可重入锁、自旋锁、偏向锁、轻量/重量级锁、读写锁、各种锁及其Java实现!
网上关于Java中锁的话题可以说资料相当丰富,但相关内容总感觉是一大串术语的罗列,让人云里雾里,读完就忘.本文希望能为Java新人做一篇通俗易懂的整合,旨在消除对各种各样锁的术语的恐惧感,对每种锁的底 ...
- 整理下线段树吧 poj hotel
除了上次的新学的有 区间更新 延迟更新 区间合并 先说下区间更新以及延迟更新吧 既然是对区间的维护 在求解一些问题的时候 有的时候没有必要对所有的自区间都进行遍历 这个时候 延迟标记就派上用场了 ( ...
- [javascript]原生js实现Ajax
一.首先看JQuery提供的Ajax方法: $.ajax({ url: , type: '', dataType: '', data: { }, success: function(){ }, err ...
- WebAPI 笔记
一.基本配置 1. 全局配置 Global.asax public class WebApiApplication : System.Web.HttpApplication { protected v ...