【详解】Spring Security 之 SecurityContext
前言
本文主要整理一下SecurityContext的存储方式。
SecurityContext接口
顾名思义,安全上下文。即存储认证授权的相关信息,实际上就是存储"当前用户"账号信息和相关权限。这个接口只有两个方法,Authentication对象的getter、setter。
package org.springframework.security.core.context; import java.io.Serializable;
import org.springframework.security.core.Authentication; public interface SecurityContext extends Serializable {
Authentication getAuthentication(); void setAuthentication(Authentication var1);
}
Authentication接口又是干嘛的?
注意:SecurityContext存储的Authentication对象是经过认证的,所以它会带有权限,它的getAuthorities()方法会返回相关权限。
package org.springframework.security.core; import java.io.Serializable;
import java.security.Principal;
import java.util.Collection; public interface Authentication extends Principal, Serializable {
Collection<? extends GrantedAuthority> getAuthorities(); Object getCredentials(); Object getDetails(); Object getPrincipal(); boolean isAuthenticated(); void setAuthenticated(boolean var1) throws IllegalArgumentException;
}
SecurityContextHolder工具类
前面说的"当前用户"实际上指的是当前这个请求所对应的用户,那么怎么知道当前用户是谁呢?由于一个请求从开始到结束都由一个线程处理,这个线程中途也不会去处理其他的请求。所以在这段时间内,相当于这个线程跟当前用户是一一对应的。SecurityContextHolder工具类就是把SecurityContext存储在当前线程中。
SecurityContextHolder可以用来设置和获取SecurityContext。它主要是给框架内部使用的,可以利用它获取当前用户的SecurityContext进行请求检查,和访问控制等。
在Web环境下,SecurityContextHolder是利用ThreadLocal来存储SecurityContext的。
请求结束,SecurityContext存储在哪里?
我们知道Sevlet中线程是被池化复用的,一旦处理完当前的请求,它可能马上就会被分配去处理其他的请求。而且也不能保证用户下次的请求会被分配到同一个线程。所以存在线程里面,请求一旦结束,就没了。如果没有保存,不是每次请求都要重新认证登录?想想看,如果没有权限框架我们是怎么处理的?
想到了吧,如果不用权限框架,我们一般是把认证结果存在Session中的。同理,它也把认证结果存储到Session了。
对应的Key是:"SPRING_SECURITY_CONTEXT"
流程视图

SecurityContextPersistenceFilter拦截器
SecurityContextPersistenceFilter是Security的拦截器,而且是拦截链中的第一个拦截器,请求来临时它会从HttpSession中把SecurityContext取出来,然后放入SecurityContextHolder。在所有拦截器都处理完成后,再把SecurityContext存入HttpSession,并清除SecurityContextHolder内的引用。
注:其中repo对象是HttpSessionSecurityContextRepository
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res; if (request.getAttribute(FILTER_APPLIED) != null) {
// ensure that filter is only applied once per request
chain.doFilter(request, response);
return;
} final boolean debug = logger.isDebugEnabled(); request.setAttribute(FILTER_APPLIED, Boolean.TRUE); if (forceEagerSessionCreation) {
HttpSession session = request.getSession(); if (debug && session.isNew()) {
logger.debug("Eagerly created session: " + session.getId());
}
} HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request,
response);
//利用HttpSecurityContextRepository从HttpSesion中获取SecurityContext对象
//如果没有HttpSession,即浏览器第一次访问服务器,还没有产生会话。
//它会创建一个空的SecurityContext对象
SecurityContext contextBeforeChainExecution = repo.loadContext(holder); try {
//把SecurityContext放入到SecurityContextHolder中
SecurityContextHolder.setContext(contextBeforeChainExecution);
//执行拦截链,这个链会逐层向下执行
chain.doFilter(holder.getRequest(), holder.getResponse()); }
finally {
//当拦截器都执行完的时候把当前线程对应的SecurityContext从SecurityContextHolder中取出来
SecurityContext contextAfterChainExecution = SecurityContextHolder
.getContext();
// Crucial removal of SecurityContextHolder contents - do this before anything
// else.
SecurityContextHolder.clearContext();
//利用HttpSecurityContextRepository把SecurityContext写入HttpSession
repo.saveContext(contextAfterChainExecution, holder.getRequest(),
holder.getResponse());
request.removeAttribute(FILTER_APPLIED); if (debug) {
logger.debug("SecurityContextHolder now cleared, as request processing completed");
}
}
}
Tomcat建立会话的流程
有人可能对Tomcat建立会话的流程还不熟悉,这里稍微整理一下。是这样的,当客户浏览器打开后第一次访问Tomcat服务器,Tomcat会创建一个HttpSesion对象,存入一个ConcurrentHashMap,Key是SessionId,Value就是HttpSession。然后请求完成后,在返回的报文中添加Set-Cookie:JSESSIONID=xxx,然后客户端浏览器会保存这个Cookie。当浏览器再次访问这个服务器的时候,都会带上这个Cookie。Tomcat接收到这个请求后,根据JSESSIONID把对应的HttpSession对象取出来,放入HttpSerlvetRequest对象里面。
重点:
1.HttpSession会一直存在服务端,实际上是存在运行内存中。除非Session过期 OR Tomcat奔溃 OR 服务器奔溃,否则会话信息不会消失。
2.如无特殊处理,Cookie JSESSIONID会在浏览器关闭的时候清除。
3.Tomcat中HttpSesion的默认过期时间为30分钟。
4.这些处理都在Security的拦截链之前完成。
——————————————————2019年1月21日更正——————————————
浏览器访问Web项目并不会创建Session,只有在编程调用request.getSession()方法后Session才会建立,浏览器才会有JSESSIONID的Cookie。
一般是认证成功后,调用getSession()(其实在这之前Session并不存在),获得Session对象,然后把信息存里面。
所以,一般的,在登录之前,你不管怎么访问网站,都不会建立会话。
【详解】Spring Security 之 SecurityContext的更多相关文章
- 详解Spring Security的HttpBasic登录验证模式
一.HttpBasic模式的应用场景 HttpBasic登录验证模式是Spring Security实现登录验证最简单的一种方式,也可以说是最简陋的一种方式.它的目的并不是保障登录验证的绝对安全,而是 ...
- 详解Spring Security的formLogin登录认证模式
一.formLogin的应用场景 在本专栏之前的文章中,已经给大家介绍过Spring Security的HttpBasic模式,该模式比较简单,只是进行了通过携带Http的Header进行简单的登录验 ...
- applicationContext.xml详解 spring+mybatis+struts
今天给大家详细解释一项关于Spring的applicationContext.xml文件,这对于初学者来说,应该是很有帮助的, 以下是详解Spring的applicationContext.xml文件 ...
- spring原理案例-基本项目搭建 02 spring jar包详解 spring jar包的用途
Spring4 Jar包详解 SpringJava Spring AOP: Spring的面向切面编程,提供AOP(面向切面编程)的实现 Spring Aspects: Spring提供的对Aspec ...
- 【转】详解spring 每个jar的作用
spring.jar 是包含有完整发布模块的单个jar 包.但是不包括mock.jar, aspects.jar, spring-portlet.jar, and spring-hibernate2. ...
- 用IDEA详解Spring中的IoC和DI(挺透彻的,点进来看看吧)
用IDEA详解Spring中的IoC和DI 一.Spring IoC的基本概念 控制反转(IoC)是一个比较抽象的概念,它主要用来消减计算机程序的耦合问题,是Spring框架的核心.依赖注入(DI)是 ...
- 使用IDEA详解Spring中依赖注入的类型(上)
使用IDEA详解Spring中依赖注入的类型(上) 在Spring中实现IoC容器的方法是依赖注入,依赖注入的作用是在使用Spring框架创建对象时动态地将其所依赖的对象(例如属性值)注入Bean组件 ...
- 详解Spring中Bean的作用域与生命周期
摘要:在利用Spring进行IOC配置时,关于bean的配置和使用一直都是比较重要的一部分,同时如何合理的使用和创建bean对象,也是小伙伴们在学习和使用Spring时需要注意的部分,所以这一篇文章我 ...
- 10分钟详解Spring全家桶7大知识点
Spring框架自2002年诞生以来一直备受开发者青睐,它包括SpringMVC.SpringBoot.Spring Cloud.Spring Cloud Dataflow等解决方案.有人亲切的称之为 ...
- [转载] 多图详解Spring框架的设计理念与设计模式
转载自http://developer.51cto.com/art/201006/205212_all.htm Spring作为现在最优秀的框架之一,已被广泛的使用,51CTO也曾经针对Spring框 ...
随机推荐
- Java Token的原理和生成使用机制
在此之前我们先了解一下什么是Cookie.Session.Token 1.什么是Cookie? cookie指的就是浏览器里面能永久存储数据的一种数据存储功能.cookie由服务器生成,发送给浏览器, ...
- (转)android import library switch语句报错case expressions must be constant expressions
今天当我从github上下载一个工程,并把它的库文件导入eclipse中,发现switch语句报错case expressions must be constant expressions : 解决方 ...
- 网络虚拟化技术(二): TUN/TAP MACVLAN MACVTAP (转)
网络虚拟化技术(二): TUN/TAP MACVLAN MACVTAP 27 March 2013 TUN 设备 TUN 设备是一种虚拟网络设备,通过此设备,程序可以方便得模拟网络行为.先来看看物理设 ...
- service 设计问题
今天写了一段让自己尴尬的代码,就是在一个方法中调用了两个 service 方法,而我为每个service 都定义了 事物回滚. 然后郁闷了,我执行请求调用该方法, 发现第二个service方法执行失败 ...
- 初级PM要做什么
首先让我们看下这张图,产品经理进入公司后将要面临着许多工作 或许你有疑问,如果是产品助理的话,上面这么多工作都要去做吗? 其实不然,初级产品经理由于工作经历有限,对行业的研究以及对市场的把控是有视野限 ...
- Java8特性之Lambda、方法引用和Streams
这里涉及三个重要特性: Lambda 方法引用 Streams ① Lambda 最早了解Lambda是在C#中,而从Java8开始,Lambda也成为了新的特性,而这个新的特性的目的,就是为了消除单 ...
- 编译搭建lnmp+zabbix
搭建nginx 1)基础依赖包安装 yum -y install gcc gcc-c++ vim tree make cmake autoconf yum -y install openssl ope ...
- Elasticsearch下安装ik分词器
安装ik分词器(必须安装maven) 上传相应jar包 解压到相应目录 unzip elasticsearch-analysis-ik-master.zip(zip包) cp -r elasticse ...
- 《Linux就该这么学》第八天课程
当一个人的心中,有着更高的山峰想要去攀登时,他就不会在意脚下的泥沼. 今天发一下干货,常用命令的一些总结,今天的理论知识比较多. 原创地址:https://www.linuxprobe.com ...
- qhfl-4 注册-登录-认证
认证 任何的项目都需要认证,当用户输入了用户名和密码,验证通过,代表用户登录成功 那HTTP请求是无状态的,下次这个用户再请求,是不可能识别这个用户是否登录的 就要有自己的方式来实现这个认证,用户登录 ...