接着上一篇来继续分析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. redis资源未释放引发的问题

    一.redis资源未释放的起因: N年前,在修改一个古老程序时,不小心把redis释放的这块给干掉了, if (jedis != null) { if (!isInProcess) { jedis.d ...

  2. java中Collections.sort()方法实现集合排序

    1.Integer/String泛型的List进行排序 List <Integer> integerlist = new ArrayList<Integer>();   //定 ...

  3. go语言时间比较

    local, _ := time.LoadLocation("Local") starttime, _ := time.ParseInLocation("2006-01- ...

  4. CentOS 6 安装HBase集群教程

    hbase0.99.2安装包下载(链接:https://pan.baidu.com/s/1dR-HB3P6mzsXVW6sLI8uxQ 密码:4g1n) 首先需要安装  zookeeper(点击查看) ...

  5. 5月2日——iOS11定位失效问题

    所存在的问题: (1)定位不能正常使用 (2)首次安装APP 时 "是否允许使用定位信息"  系统提示框不显示 iOS定位失效原因: 因为苹果现在增加了一项新的隐私保护功能 NSL ...

  6. python之Flask实现登录功能

    网站少不了要和数据库打交道,归根到底都是一些增删改查操作,这里做一个简单的用户登录功能来学习一下Flask如何操作MySQL. 用到的一些知识点:Flask-SQLAlchemy.Flask-Logi ...

  7. 【机器学习】使用gensim 的 doc2vec 实现文本相似度检测

    环境 Python3, gensim,jieba,numpy ,pandas 原理:文章转成向量,然后在计算两个向量的余弦值. Gensim gensim是一个python的自然语言处理库,能够将文档 ...

  8. 微信小程序开发资源汇总 💯

    目录 官方文档 工具 插件 讨论 教程 视频教程 文章 代码 轮子 置顶 WePY:组件化的小程序开发框架 

  9. 可能是史上最全的机器学习和Python(包括数学)速查表

    新手学习机器学习很难,就是收集资料也很费劲.所幸Robbie Allen从不同来源收集了目前最全的有关机器学习.Python和相关数学知识的速查表大全.强烈建议收藏! 机器学习有很多方面. 当我开始刷 ...

  10. 十七、Hadoop学记笔记————Hbase入门

    简而言之,Hbase就是一个建立在Hdfs文件系统上的数据库(mysql,orecle等),不同的是Hbase是针对列的数据库 Hbase和普通的关系型数据库区别如下: Hbase有一些基本的术语,主 ...