接着上一篇来继续分析shiro源码

这篇主要讲解shiro里面的SecurityUtils

首先我们看该类供我们在业务中用的仅有两个get方法,那么这两个get方法获取的subject和sercurityManager怎么来的,我们具体分析

首先我们已经知道每次请求在被拦截后都会走AbstractShiroFilter里的doFilterInternal方法,如果不清楚请先看我的《spring集成shiro登陆流程》的上下篇。

AbstractShiroFilter

其中有这么段代码

//调用DelegatingSubject的execute(Callable<V> callable)方法
subject.execute(new Callable() {
  public Object call() throws Exception {
    updateSessionLastAccessTime(request, response);
    executeChain(request, response, chain);
    return null;
}
});

这里调用了DelegatingSubject的execute(Callable<V> callable)方法

DelegatingSubject

进来看

public <V> V execute(Callable<V> callable) throws ExecutionException {
    //这里创建了一个Callable对象,进去看
Callable<V> associated = associateWith(callable);
try {
return associated.call();
} catch (Throwable t) {
throw new ExecutionException(t);
}
}
//继续
public <V> Callable<V> associateWith(Callable<V> callable) {
  //这里将subject对象传递到SubjectCallable
  return new SubjectCallable<V>(this, callable);
}
 

SubjectCallable

注意看这里创建了一个SubjectThreadState对象

public SubjectCallable(Subject subject, Callable<V> delegate) {
this(new SubjectThreadState(subject), delegate);
} //这个方法主要是将subject对象和securityManager 放在SubjectThreadState上下文
public SubjectThreadState(Subject subject) {
    this.subject = subject;

    SecurityManager securityManager = null;
  //从subject中获取securityManager对象,每次请求都会将securityManager对象放到subject上下文, (DefaultSecurityManager#createSubject的ensureSecurityManager)
if ( subject instanceof DelegatingSubject) {
securityManager = ((DelegatingSubject)subject).getSecurityManager();
}
if ( securityManager == null) {
securityManager = ThreadContext.getSecurityManager();
}
this.securityManager = securityManager;
}

 那么到这儿,在SubjectThreadState中就有了subject和securityManager对象

继续看到DelegatingSubject的execute方法

执行associated.call()

我们点进去看  SubjectCallable#call

SubjectCallable

//首先我们注意到doCall方法就是调用了Callable的call方法,也就是异步执行了executeChain(request, response, chain);方法,简单说就是调用验证等流水账然后进入我们的业务代码
//我们调用SecurityUtis.getSubject就是在doCall异步执行里用的
public V call() throws Exception {
try {
        //我们发现执行目标业务之前有个bind方法
threadState.bind();
return doCall(this.callable);
} finally {
       //执行完后会清空bind的数据
threadState.restore();
}
}
protected V doCall(Callable<V> target) throws Exception {
return target.call();
}

很有必要再进SubjectThreadState方法看看bind这个方法

SubjectThreadState

public void bind() {
SecurityManager securityManager = this.securityManager;this.originalResources = ThreadContext.getResources();
    //清空ThreadContext里的数据
ThreadContext.remove();
    //将subject和securityManager绑定到ThreadContext
ThreadContext.bind(this.subject);
if (securityManager != null) {
ThreadContext.bind(securityManager);
}
}

走到这儿我们发现把subject和securityManager绑定到ThreadContext

那么这个ThreadContext就很重要了,必须看看

ThreadContext

//定义了个跟线程绑定的ThreadLocal
private static final ThreadLocal<Map<Object, Object>> resources = new InheritableThreadLocalMap<Map<Object, Object>>();

//将subject和当前线程绑定
public static void bind(Subject subject) {
if (subject != null) {
put(SUBJECT_KEY, subject);
}
}
//将securityManager和当前线程绑定
public static void bind(SecurityManager securityManager) {
if (securityManager != null) {
put(SECURITY_MANAGER_KEY, securityManager);
}
}

那么我们应该再看看SecurityUtils的两个get方法

//从ThreadContext中获取,没有就创建一个并绑定
public static Subject getSubject() {
Subject subject = ThreadContext.getSubject();
if (subject == null) {
subject = (new Subject.Builder()).buildSubject();
ThreadContext.bind(subject);
}
return subject;
}
//先从ThreadContext中获取,如果没有则从SecurityUtils中获取,如果没有就直接从SubjceUtils中获取(如果是spring项目,那么在spirng的配置文件长会配置)
public static SecurityManager getSecurityManager() throws UnavailableSecurityManagerException {
SecurityManager securityManager = ThreadContext.getSecurityManager();
if (securityManager == null) {
securityManager = SecurityUtils.securityManager;
}return securityManager;
}

看到这儿我们了解到了为什么我们在程序中调用SecurityUtils的getSubject会有值了

小结:

  当我们登陆后,每次请求都会将Subject对象和SecurityManager对象与当前线程绑定,在执行完业务逻辑后,会将这些数据与当前线程解绑

  那么我们得到了SecurityManager对象后,那么它依赖的数据就轻而易举的可以愉快的拿到了

注:有不好或者错误的地方还请看官在评论区给指出,意见宝贵。

shiro的SecurityUtis的更多相关文章

  1. Shiro learning - 入门案例(2)

    Shiro小案例 在上篇Shiro入门学习中说到了Shiro可以完成认证,授权等流程.在学习认证流程之前,我们应该先入门一个Shiro小案例. 创建一个java maven项目 <?xml ve ...

  2. shiro权限管理框架与springmvc整合

    shiro是apache下的一个项目,和spring security类似,用于用户权限的管理‘ 但从易用性和学习成本上考虑,shiro更具优势,同时shiro支持和很多接口集成 用户及权限管理是众多 ...

  3. springmvc 多数据源 SSM java redis shiro ehcache 头像裁剪

    获取下载地址   QQ 313596790  A 调用摄像头拍照,自定义裁剪编辑头像 B 集成代码生成器 [正反双向](单表.主表.明细表.树形表,开发利器)+快速构建表单;  技术:31359679 ...

  4. java springMVC SSM 操作日志 4级别联动 文件管理 头像编辑 shiro redis

    A 调用摄像头拍照,自定义裁剪编辑头像 B 集成代码生成器 [正反双向](单表.主表.明细表.树形表,开发利器)+快速构建表单;  技术:313596790freemaker模版技术 ,0个代码不用写 ...

  5. springmvc SSM shiro redis 后台框架 多数据源 代码生成器

    A集成代码生成器 [正反双向(单表.主表.明细表.树形表,开发利器)+快速构建表单 下载地址    ; freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本,处理类 ...

  6. springmvc SSM 多数据源 shiro redis 后台框架 整合

    A集成代码生成器 [正反双向(单表.主表.明细表.树形表,开发利器)+快速构建表单 下载地址    ; freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面.建表sql脚本,处理类 ...

  7. SpringMVC+Shiro权限管理【转】

    1.权限的简单描述 2.实例表结构及内容及POJO 3.Shiro-pom.xml 4.Shiro-web.xml 5.Shiro-MyShiro-权限认证,登录认证层 6.Shiro-applica ...

  8. shiro的使用2 灵活使用shiro的密码服务模块

    shiro最闪亮的四大特征是认证,授权,加密,会话管理. 上一篇已经演示了如何使用shiro的授权模块,有了shiro这个利器,可以以统一的编码方式对用户的登入,登出,认证进行管理,相当的优雅. 为了 ...

  9. shiro的使用1 简单的认证

    最近在重构,有空学了一个简单的安全框架shiro,资料比较少,在百度和google上能搜到的中文我看过了,剩下的时间有空会研究下官网的文章和查看下源码, 简单的分享一些学习过程: 1,简单的一些概念上 ...

随机推荐

  1. Kotlin : Retrofit + RxAndroid + Realm

    https://jqs7.com/kotlin-retrofit-rxandroid-realm/ 原作者:Ahmed Rizwan 原文链接:Kotlin : Retrofit + RxAndroi ...

  2. meta 刷新

    <meta http-equiv="refresh" content="5;url=地址" /> 5秒后刷新至URL地址

  3. 学习JavaScript最佳实践方法

    首先要说明的是,咱现在不是高手,最多还是一个半桶水,算是入了JS的门. 谈不上经验,都是一些教训. 这个时候有人要说,“靠,你丫半桶水,凭啥教我们”.您先别急着骂,先听我说. 你叫一个大学生去教小学数 ...

  4. C# Dispose模式详细分析

    C#Dispose模式 目的: 为了及时释放宝贵的非托管资源和托管资源,并且保证资源在被gc回收的时候可以正确释放资源,同时兼顾执行效率 必须遵循的事实: 1 托管资源释放: 由另一线程的gc进行释放 ...

  5. java动态绑定与静态绑定【转】

    程序绑定的概念: 绑定指的是一个方法的调用与方法所在的类(方法主体)关联起来.对java来说,绑定分为静态绑定和动态绑定:或者叫做前期绑定和后期绑定.静态绑定: 在程序执行前方法已经被绑定(也就是说在 ...

  6. 使用pypi-server搭建简单的PyPI源

    pypiserver 是一个最基本的PyPI服务器实现, 可以用来上传和维护python包. 本文介绍 pypiserver 在ubuntu上的基本安装, 配置和使用. 1. 基本安装和使用 1.1 ...

  7. spring boot入门篇,helloworld案例演示

    为什么用spring boot? 嵌入的 Tomcat,无需部署 WAR 文件 简化 Maven 配置 无需 XML 配置,轻松快速地搭建Spring Web应用 开始学习SpringBoot 构建简 ...

  8. Java IO流对象、多线程

    Input(读) Output(写)操作 File类 import java.io.File; 将操作系统中的文件.目录(文件夹).路径.封装成File对象 提供方法,操作系统中的内容.File与系统 ...

  9. Python(Django)项目与Apache的管理交互

    (开开心心每一天~ ---虫瘾师) Python(Django)项目交给Apache的管理(一) 准备:Django的环境(Python).Apache.Wsgi(必须文件) 首先需要电脑有Pytho ...

  10. Netty 笔记

    1.Netty 是一款异步的事件驱动的网络应用程序框架,支持快速地开发可维护的高性能的面向协议的服务器和客户端. 2.早期Java API 使用的阻塞函数 // 创建一个新的ServerSocket, ...