在springsecurity 中,我们一般可以通过代码:

SecurityContext securityContext = SecurityContextHolder.getContext();

Authentication auth = securityContext.getAuthentication();

获取当前登录人员信息,其实我们可以从SecurityContext 获取 springsecurity 实现的秘密。

就让我从SecurityContextHolder 一步步抽丝剥茧,解读一下SecurityContext  的来源。

这里我们可以通过查看SecurityContextHolder 源码,看看这个SecurityContext  到底 是哪里来的。

 public static void clearContext() {
strategy.clearContext();
} /**
* Obtain the current <code>SecurityContext</code>.
*
* @return the security context (never <code>null</code>)
*/
public static SecurityContext getContext() {
return strategy.getContext();
}
public static void setContext(SecurityContext context) {
strategy.setContext(context);
}

代码很简单,我们可以看到他是通过 strategy 获取 的,那这个strategy 有是什么东西呢?

通过跟踪 源码发现 ,这个 strategy 实际是ThreadLocalSecurityContextHolderStrategy 的一个实例对象。

那这个ThreadLocalSecurityContextHolderStrategy  又是什么呢,我们继续看源码。

final class ThreadLocalSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
//~ Static fields/initializers ===================================================================================== private static final ThreadLocal<SecurityContext> contextHolder = new ThreadLocal<SecurityContext>(); //~ Methods ======================================================================================================== public void clearContext() {
contextHolder.remove();
} public SecurityContext getContext() {
SecurityContext ctx = contextHolder.get(); if (ctx == null) {
ctx = createEmptyContext();
contextHolder.set(ctx);
} return ctx;
} public void setContext(SecurityContext context) {
Assert.notNull(context, "Only non-null SecurityContext instances are permitted");
contextHolder.set(context);
} public SecurityContext createEmptyContext() {
return new SecurityContextImpl();
}
}

不过就是一个放到一个线程变量中。看到这里我们需要知道 什么使用调用了这个setContext 方法。

通过跟踪源码发现:原来调用这个setContext方法的类:

SecurityContextPersistenceFilter

这是一个过滤器。我们知道 springsecurity 是有一组 过滤器 组成的,并且这个过滤器排在这些过滤器的第一个位置。

这个我们终于找到设置这个context的源头了。

通过阅读源码 ,我们看到这样两行代码.

HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request, response);
SecurityContext contextBeforeChainExecution = repo.loadContext(holder);

我们看到了这个SecurityContext 的源头了。

我们找到了这个 SecurityContext 是通过这个SecurityContextRepository 类获取的。

我们找到了这个接口的实现 HttpSessionSecurityContextRepository。

public SecurityContextPersistenceFilter() {
this(new HttpSessionSecurityContextRepository());
} public SecurityContextPersistenceFilter(SecurityContextRepository repo) {
this.repo = repo;
}

最终我们找到了HttpSessionSecurityContextRepository代码

 private SecurityContext readSecurityContextFromSession(HttpSession httpSession) {
final boolean debug = logger.isDebugEnabled(); if (httpSession == null) {
if (debug) {
logger.debug("No HttpSession currently exists");
} return null;
} // Session exists, so try to obtain a context from it. Object contextFromSession = httpSession.getAttribute(springSecurityContextKey); if (contextFromSession == null) {
if (debug) {
logger.debug("HttpSession returned null object for SPRING_SECURITY_CONTEXT");
} return null;
} // We now have the security context object from the session.
if (!(contextFromSession instanceof SecurityContext)) {
if (logger.isWarnEnabled()) {
logger.warn(springSecurityContextKey + " did not contain a SecurityContext but contained: '"
+ contextFromSession + "'; are you improperly modifying the HttpSession directly "
+ "(you should always use SecurityContextHolder) or using the HttpSession attribute "
+ "reserved for this class?");
} return null;
} if (debug) {
logger.debug("Obtained a valid SecurityContext from " + springSecurityContextKey + ": '" + contextFromSession + "'");
} // Everything OK. The only non-null return from this method. return (SecurityContext) contextFromSession;
}

这里我们可以看到 实际 这个SecurityContext 实际是从session 中获取的。

Object contextFromSession = httpSession.getAttribute("SPRING_SECURITY_CONTEXT");

从这里我们就知道了这个SecurityContext 来源了。

步骤是:

1.通过 SecurityContextPersistenceFilter 这个过滤器,从session 中获取SecurityContext .

2.并且把这个SecurityContext  放到线程变量中,然后我们在这个请求中就可以直接通过SecurityContextHolder.getContext();

获取SecurityContext 对象了。

解决了获取的问题,我们只需要把登录后的SecurityContext  放到httpsession 中就好了。

下面代码就是登录的代码实现:

UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(userName, pwd);
authRequest.setDetails(new WebAuthenticationDetails(request));
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication auth = authenticationManager.authenticate(authRequest);
securityContext.setAuthentication(auth); HttpSession session = request.getSession();
session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, securityContext);

通过上面的代码,我们就将securityContext 放到 session中了。

springsecurity 源码解读之 SecurityContext的更多相关文章

  1. springsecurity 源码解读 之 RememberMeAuthenticationFilter

    RememberMeAuthenticationFilter 的作用很简单,就是用于当session 过期后,系统自动通过读取cookie 让系统自动登录. 我们来看看Springsecurity的过 ...

  2. springsecurity 源码解读之 AnonymousAuthenticationFilter

    我们知道springsecutity 是通过一系列的 过滤器实现的,我们可以看看这系列的过滤器到底长成什么样子呢? 一堆过滤器,这个过滤器的设计设计上是 责任链设计模式. 这里我们可以看到有一个 An ...

  3. SDWebImage源码解读之SDWebImageDownloaderOperation

    第七篇 前言 本篇文章主要讲解下载操作的相关知识,SDWebImageDownloaderOperation的主要任务是把一张图片从服务器下载到内存中.下载数据并不难,如何对下载这一系列的任务进行设计 ...

  4. SDWebImage源码解读 之 NSData+ImageContentType

    第一篇 前言 从今天开始,我将开启一段源码解读的旅途了.在这里先暂时不透露具体解读的源码到底是哪些?因为也可能随着解读的进行会更改计划.但能够肯定的是,这一系列之中肯定会有Swift版本的代码. 说说 ...

  5. SDWebImage源码解读 之 UIImage+GIF

    第二篇 前言 本篇是和GIF相关的一个UIImage的分类.主要提供了三个方法: + (UIImage *)sd_animatedGIFNamed:(NSString *)name ----- 根据名 ...

  6. SDWebImage源码解读 之 SDWebImageCompat

    第三篇 前言 本篇主要解读SDWebImage的配置文件.正如compat的定义,该配置文件主要是兼容Apple的其他设备.也许我们真实的开发平台只有一个,但考虑各个平台的兼容性,对于框架有着很重要的 ...

  7. SDWebImage源码解读_之SDWebImageDecoder

    第四篇 前言 首先,我们要弄明白一个问题? 为什么要对UIImage进行解码呢?难道不能直接使用吗? 其实不解码也是可以使用的,假如说我们通过imageNamed:来加载image,系统默认会在主线程 ...

  8. SDWebImage源码解读之SDWebImageCache(上)

    第五篇 前言 本篇主要讲解图片缓存类的知识,虽然只涉及了图片方面的缓存的设计,但思想同样适用于别的方面的设计.在架构上来说,缓存算是存储设计的一部分.我们把各种不同的存储内容按照功能进行切割后,图片缓 ...

  9. SDWebImage源码解读之SDWebImageCache(下)

    第六篇 前言 我们在SDWebImageCache(上)中了解了这个缓存类大概的功能是什么?那么接下来就要看看这些功能是如何实现的? 再次强调,不管是图片的缓存还是其他各种不同形式的缓存,在原理上都极 ...

随机推荐

  1. html/css/js-横向滚动条的实现

    在前端UI设计时,网页的制作很麻烦,深有感悟!碰到太多的不懂,或是第一次见,就要去网上找资料!横向滚动条就是我遇到麻烦中其中的一个,其实也 很简单,只是在几次项目中都用到了这个横向滚动条所以就拿出来说 ...

  2. asp.net web api 权限验证的方法

    思路:客户端使用header或者form讲验证信息传入api,在权限验证过滤中进行处理,代码示例: 定义过滤器 public class ApiFilter1 : System.Web.Http.Au ...

  3. Shiro+CAS

    参考链接: CAS实现单点登录SSO执行原理探究:http://blog.csdn.net/javaloveiphone/article/details/52439613 单点登录CAS技术概述:ht ...

  4. 第二章 FFmpeg常用命令

    2.1 FFmpeg常见的命令大概分为6个部分 ffmpeg信息查询部分 公共操作参数部分 文件主要操作参数部分 视频操作参数部分 字幕操作参数部分 2.1.1 FFmpeg的封装转换 FFmpeg ...

  5. [java,2017-05-04] 合并word文档

    import java.io.File; import com.aspose.words.Document; import com.aspose.words.ImportFormatMode; pub ...

  6. [持续交付实践] pipeline使用:项目样例

    项目说明 本文将以一个微服务项目的具体pipeline样例进行脚本编写说明.一条完整的pipeline交付流水线通常会包括代码获取.单元测试.静态检查.打包部署.接口层测试.UI层测试.性能专项测试( ...

  7. Django多个中间件的执行顺序

    Django中的中间件是一个轻量级.底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出.中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django框架的健 ...

  8. uva-10400-搜索

    题意:题意很简单,就是输入数字,对数字进行加减乘除,然后能不能得到最后的数字. wa了很多次,memcpy(dst,src,sizeof(dst))才对,最后一个参数写错,最后一个参数是要拷贝的字节数 ...

  9. CSS vertical-align属性详解

    . 首页 博客园 联系我 前言:关于vertical-align属性. 实践出真知. 垂直居中. 第二种用法. 留言评论 返回顶部 前言:关于vertical-align属性 vertical-ali ...

  10. css:常见布局问题

    一.单列布局 1. 水平居中 1.1 使用inline-block和text-align .parent{text-align:center;} .child{display:inline-block ...