在 request 之间共享 SecurityContext
来源:互联网 发布:时间浪人网络大电影 编辑:程序博客网 时间:2024/06/17 03:42
引言
既然 SecurityContext 是存放在 ThreadLocal 中的,而且在每次权限鉴定的时候都是从 ThreadLocal 中获取 SecurityContext 中对应的 Authentication 所拥有的权限,并且不同的 request 是不同的线程,为什么每次都可以从 ThreadLocal 中获取到当前用户对应的 SecurityContext 呢?
入题
在 Web 应用中这是通过 SecurityContextPersistentFilter 实现的,默认情况下其会在每次请求开始的时候从 session 中获取 SecurityContext,然后把它设置给 SecurityContextHolder,在请求结束后又会将 SecurityContextHolder 所持有的 SecurityContext 保存在 session 中,并且清除 SecurityContextHolder 所持有的 SecurityContext。这样当我们第一次访问系统的时候,SecurityContextHolder 所持有的 SecurityContext 肯定是空的,待我们登录成功后,SecurityContextHolder 所持有的 SecurityContext 就不是空的了,且包含有认证成功的 Authentication 对象,待请求结束后我们就会将 SecurityContext 存在 session 中,等到下次请求的时候就可以从 session 中获取到该 SecurityContext 并把它赋予给 SecurityContextHolder 了,由于 SecurityContextHolder 已经持有认证过的 Authentication 对象了,所以下次访问的时候也就不再需要进行登录认证了。
相关代码
//Stores the supplied security context in the session
protected voidsaveContext(SecurityContext context) {
final Authentication authentication = context.getAuthentication();
HttpSession httpSession = request.getSession(false);
// See SEC-776
if (authentication == null || authenticationTrustResolver.isAnonymous(authentication)) {
if (logger.isDebugEnabled()) {
logger.debug("SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.");
}
if (httpSession != null && !contextObject.equals(contextBeforeExecution)) {
// SEC-1587 A non-anonymous context may still be in the session
// SEC-1735 remove if the contextBeforeExecution was not anonymous
httpSession.removeAttribute(springSecurityContextKey);
}
return;
}
if (httpSession == null) {
httpSession = createNewSessionIfAllowed(context);
}
// If HttpSession exists, store current SecurityContext but only if it has
// actually changed in this thread (see SEC-37, SEC-1307, SEC-1528)
if (httpSession != null) {
// We may have a new session, so check also whether the context attribute is set SEC-1561
if (contextChanged(context) || httpSession.getAttribute(springSecurityContextKey) == null) {
httpSession.setAttribute(springSecurityContextKey, context);
if (logger.isDebugEnabled()) {
logger.debug("SecurityContext stored to HttpSession: '" + context + "'");
}
}
}
}
final Authentication authentication = context.getAuthentication();
HttpSession httpSession = request.getSession(false);
// See SEC-776
if (authentication == null || authenticationTrustResolver.isAnonymous(authentication)) {
if (logger.isDebugEnabled()) {
logger.debug("SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.");
}
if (httpSession != null && !contextObject.equals(contextBeforeExecution)) {
// SEC-1587 A non-anonymous context may still be in the session
// SEC-1735 remove if the contextBeforeExecution was not anonymous
httpSession.removeAttribute(springSecurityContextKey);
}
return;
}
if (httpSession == null) {
httpSession = createNewSessionIfAllowed(context);
}
// If HttpSession exists, store current SecurityContext but only if it has
// actually changed in this thread (see SEC-37, SEC-1307, SEC-1528)
if (httpSession != null) {
// We may have a new session, so check also whether the context attribute is set SEC-1561
if (contextChanged(context) || httpSession.getAttribute(springSecurityContextKey) == null) {
httpSession.setAttribute(springSecurityContextKey, context);
if (logger.isDebugEnabled()) {
logger.debug("SecurityContext stored to HttpSession: '" + context + "'");
}
}
}
}
//
private SecurityContextreadSecurityContextFromSession(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;
}
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;
}
重点看上面颜色标注部分代码!
阅读全文
0 0
- 在 request 之间共享 SecurityContext
- 在页面之间共享代码
- scrapy在Request之间传递参数
- 如何在进程之间共享内核对象
- 在Exe和Dll之间共享变量
- iOS, 在应用之间共享文档。
- VC++入门:在变量之间共享内存
- iOS,在应用之间共享文档
- ios:在应用之间共享文档。
- IOS在app之间共享文件
- 如何在linux系统之间共享文件
- 在Ubuntu和Windows之间共享文件夹
- 在多个Activity之间共享变量
- samba在linux之间共享文件挂载报错
- 在多个的共享ndk项目之间共享模块
- scrapy 在不同的Request之间传递参数的办法
- Scrapy抓取在不同级别Request之间传递参数
- scrapy 在不同的Request之间传递参数的办法
- 【Selenium】11异常
- 希尔排序(Shell Sort)
- Spring Bean加载过程
- 51Nod 1298:圆与三角形(计算几何)
- 动态规划:word-break
- 在 request 之间共享 SecurityContext
- lower_bound与upper_bound
- 不安装oracle客户端使用plsql
- (2017多校训练第六场)HDU
- 手把手教你AndroidStudio多渠道打包
- Ambari-2.2.2.0文档翻译--准备工作(2)
- C++命名空间 namespace的作用和使用解析
- Hive SerDe 使用
- 基于继承的初始化学习