在某些时候我们需要创建会话(HttpSession)来帮我们维持某些状态信息。例如当用户登录后在会话中记录用户的登录信息、或者存储一些用户数据等。Session本身是由Servlet容器进行管理,在内部可以完成Session的创建、销毁等, 当达到了会话的最大非活动间隔时长,那么会话会在服务器端会被失效。
Spring Security的会话管理并不是管理Session的创建销毁等工作,其主要用途大致有以下两点
- 单用户session的并发数限制与处理【一个用户多个地方登陆】
处理方例如:
1)超过限制跳转到指定的地址
2)确定最近最少使用的会话,并将其标记为无效 - 激活会话固定保护机制,防止会话固定攻击
默认配置里面是包含对session进行管理的内容的,如下sessionManagement()所示
http
.csrf().and()
.addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling().and()
.headers().and()
.sessionManagement().and()
.securityContext().and()
.requestCache().and()
.anonymous().and()
.servletApi().and()
.apply(new DefaultLoginPageConfigurer<>()).and()
.logout();
在调用sessionManagement()进行配置时,实际上是使用了SessionManagementConfigurer配置对象,如下方法所示
public SessionManagementConfigurer<HttpSecurity> sessionManagement() throws Exception {
return getOrApply(new SessionManagementConfigurer<>());
}
SessionManagementConfigurer的源码如下
public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<SessionManagementConfigurer<H>, H> {
//调用下面的方法得到ChangeSessionIdAuthenticationStrategy
private final SessionAuthenticationStrategy DEFAULT_SESSION_FIXATION_STRATEGY = createDefaultSessionFixationProtectionStrategy();
private SessionAuthenticationStrategy sessionFixationAuthenticationStrategy = this.DEFAULT_SESSION_FIXATION_STRATEGY;
//会话认证(是否满足会话配置要求)策略
private SessionAuthenticationStrategy sessionAuthenticationStrategy;
private SessionAuthenticationStrategy providedSessionAuthenticationStrategy;
//失效会话策略,如跳转到指定地址【SimpleRedirectInvalidSessionStrategy】
private InvalidSessionStrategy invalidSessionStrategy;
//用户会话信息过期策略【维护SessionInformation对象】
private SessionInformationExpiredStrategy expiredSessionStrategy;
//会话认证(是否满足会话配置要求)策略【下面的代码会陆续加入多个】
private List<SessionAuthenticationStrategy> sessionAuthenticationStrategies = new ArrayList<>();
//用户会话信息注册
private SessionRegistry sessionRegistry;
//最大会话数
private Integer maximumSessions;
//过期的Url
private String expiredUrl;
//是否达到最大会话数时阻止登录
private boolean maxSessionsPreventsLogin;
//会话创建策略
private SessionCreationPolicy sessionPolicy;
//是否启用会话Url重写
private boolean enableSessionUrlRewriting;
//无效的会话Url
private String invalidSessionUrl;
//会话身份验证错误URL
private String sessionAuthenticationErrorUrl;
private AuthenticationFailureHandler sessionAuthenticationFailureHandler;
public SessionManagementConfigurer() {}
private static SessionAuthenticationStrategy createDefaultSessionFixationProtectionStrategy() {
// 默认使用HttpServletRequest.changeSessionId()防止会话固定攻击
return new ChangeSessionIdAuthenticationStrategy();
}
//根据session的创建策略来判断,例如:总是创建【ALWAYS】、需要时创建【IF_REQUIRED】、
//永不创建【STATELESS】 、永不创建但如有则使用【NEVER】
private boolean isStateless() {
SessionCreationPolicy sessionPolicy = getSessionCreationPolicy();
return SessionCreationPolicy.STATELESS == sessionPolicy;
}
//是否允许创建session
private boolean isAllowSessionCreation() {
SessionCreationPolicy sessionPolicy = getSessionCreationPolicy();
return SessionCreationPolicy.ALWAYS == sessionPolicy
|| SessionCreationPolicy.IF_REQUIRED == sessionPolicy;
}
SessionCreationPolicy getSessionCreationPolicy() {
if (this.sessionPolicy != null) {
return this.sessionPolicy;
}
SessionCreationPolicy sessionPolicy =
getBuilder().getSharedObject(SessionCreationPolicy.class);
return sessionPolicy == null ?
SessionCreationPolicy.IF_REQUIRED : sessionPolicy;
}
@Override
public void init(H http) {
//获取存储SecurityContext的存储库
//HttpSessionSecurityContextRepository、NullSecurityContextRepository
SecurityContextRepository securityContextRepository = http
.getSharedObject(SecurityContextRepository.class);
//得到SessionCreationPolicy实例并判断策略(从属性或SharedObject中得到)
boolean stateless = isStateless();
if (securityContextRepository == null) {
if (stateless) {
//设置默认值
http.setSharedObject(SecurityContextRepository.class,
new NullSecurityContextRepository());
} else {
HttpSessionSecurityContextRepository httpSecurityRepository = new HttpSessionSecurityContextRepository();
//是否禁止URL的重写
httpSecurityRepository
.setDisableUrlRewriting(!this.enableSessionUrlRewriting);
//是否允许创建Session(当策略为ALWAYS或IF_REQUIRED时即可创建)
httpSecurityRepository.setAllowSessionCreation(isAllowSessionCreation());
//获取用于对身份令牌进行验证的解析类【anonymous、rememberMe】(AuthenticationTrustResolverImpl)
AuthenticationTrustResolver trustResolver = http
.getSharedObject(AuthenticationTrustResolver.class);
if (trustResolver != null) {
httpSecurityRepository.setTrustResolver(trustResolver);
}
http.setSharedObject(SecurityContextRepository.class,
httpSecurityRepository);
}
}
//实现“保存请求”逻辑,请求被重定向到某身份认证机制返回后,允许该请求可以被取到并继续后续的请求。
//(HttpSessionRequestCache、NullRequestCache)
RequestCache requestCache = http.getSharedObject(RequestCache.class);
if (requestCache == null) {
if (stateless) {
http.setSharedObject(RequestCache.class, new NullRequestCache());
}
}
//这里需要关注,会使用到maximumSessions属性来控制会话数
http.setSharedObject(SessionAuthenticationStrategy.class,
getSessionAuthenticationStrategy(http)); //CompositeSessionAuthenticationStrategy
//创建会话失效策略【执行重定向到固定URL】
http.setSharedObject(InvalidSessionStrategy.class, getInvalidSessionStrategy());
}
@Override
public void configure(H http) {
SecurityContextRepository securityContextRepository = http
.getSharedObject(SecurityContextRepository.class);
//创建用于会话管理的过滤器【关键】
SessionManagementFilter sessionManagementFilter = new SessionManagementFilter(
securityContextRepository, getSessionAuthenticationStrategy(http));
if (this.sessionAuthenticationErrorUrl != null) {
//会话验证错误跳转地址
sessionManagementFilter.setAuthenticationFailureHandler(
new SimpleUrlAuthenticationFailureHandler(
this.sessionAuthenticationErrorUrl));
}
/**
*会话失效管理策略;
*
*SimpleRedirectInvalidSessionStrategy:当检测到无效的请求会话时,
*执行重定向到固定URL
*/
InvalidSessionStrategy strategy = getInvalidSessionStrategy();
if (strategy != null) {
sessionManagementFilter.setInvalidSessionStrategy(strategy);
}
//会话验证失败处理器
AuthenticationFailureHandler failureHandler = getSessionAuthenticationFailureHandler();
if (failureHandler != null) {
sessionManagementFilter.setAuthenticationFailureHandler(failureHandler);
}
//身份验证令牌验证
AuthenticationTrustResolver trustResolver = http
.getSharedObject(AuthenticationTrustResolver.class);
if (trustResolver != null) {
sessionManagementFilter.setTrustResolver(trustResolver);
}
sessionManagementFilter = postProcess(sessionManagementFilter);
//往HttpSecurity实例中添加会话管理的Filter
http.addFilter(sessionManagementFilter);
if (isConcurrentSessionControlEnabled()) { //如果maximumSessions属性不为空
//对Session的并发量(同用户打开的session数)进行控制
//【如果maximumSessions属性不为空】
ConcurrentSessionFilter concurrentSessionFilter = createConcurrencyFilter(http);
concurrentSessionFilter = postProcess(concurrentSessionFilter);
//往HttpSecurity实例中添加Filter
http.addFilter(concurrentSessionFilter);
}
}
InvalidSessionStrategy getInvalidSessionStrategy() {
if (this.invalidSessionStrategy != null) { //默认为空
return this.invalidSessionStrategy;
}
if (this.invalidSessionUrl != null) { //默认为空
//创建会话失效策略【执行重定向到固定URL】
this.invalidSessionStrategy = new SimpleRedirectInvalidSessionStrategy(
this.invalidSessionUrl);
}
if (this.invalidSessionUrl == null) {
return null;
}
if (this.invalidSessionStrategy == null) {
this.invalidSessionStrategy = new SimpleRedirectInvalidSessionStrategy(
this.invalidSessionUrl);
}
return this.invalidSessionStrategy;
}
//得到会话验证策略【CompositeSessionAuthenticationStrategy】
private SessionAuthenticationStrategy getSessionAuthenticationStrategy(H http) {
if (this.sessionAuthenticationStrategy != null) { //默认为空
return this.sessionAuthenticationStrategy;
}
//集合实例
List<SessionAuthenticationStrategy> delegateStrategies = this.sessionAuthenticationStrategies;
//创建默认的会话认证测试,默认使用sessionFixationAuthenticationStrategy【ChangeSessionIdAuthenticationStrategy】
SessionAuthenticationStrategy defaultSessionAuthenticationStrategy;
if (this.providedSessionAuthenticationStrategy == null) { //默认为空
// If the user did not provide a SessionAuthenticationStrategy
// then default to sessionFixationAuthenticationStrategy
defaultSessionAuthenticationStrategy = postProcess(
this.sessionFixationAuthenticationStrategy);
}
else {
defaultSessionAuthenticationStrategy = this.providedSessionAuthenticationStrategy;
}
//是否允许并发会话控制(通过判断maximumSessions属性是否为空,默认为空-即不控制)
if (isConcurrentSessionControlEnabled()) {
//默认使用SessionRegistryImpl,监听ApplicationContext的SessionDestroyedEvent事件
SessionRegistry sessionRegistry = getSessionRegistry(http);
//使用sessionRegistry构建ConcurrentSessionControlAuthenticationStrategy实例
//内部会调用sessionRegistry的getAllSessions方法得到登录用户的所有session,然后判断个数是否超出限制,
ConcurrentSessionControlAuthenticationStrategy concurrentSessionControlStrategy = new ConcurrentSessionControlAuthenticationStrategy(
sessionRegistry);
//设置限制的并发会话数
concurrentSessionControlStrategy.setMaximumSessions(this.maximumSessions);
//是否阻止用户打开超出允许的会话。
//如果设置为true,将引发SessionAuthenticationException,这意味着将阻止用户身份验证。
//如果设置为false,则将确定最近最少使用的会话,并将其标记为无效。默认false。
concurrentSessionControlStrategy
.setExceptionIfMaximumExceeded(this.maxSessionsPreventsLogin);
concurrentSessionControlStrategy = postProcess(
concurrentSessionControlStrategy);
//使用sessionRegistry创建RegisterSessionAuthenticationStrategy实例。
//用于在成功验证后向SessionRegistry注册用户的策略(执行sessionRegistry的registerNewSession方法)
RegisterSessionAuthenticationStrategy registerSessionStrategy = new RegisterSessionAuthenticationStrategy(
sessionRegistry);
registerSessionStrategy = postProcess(registerSessionStrategy);
//将上面创建的三个策略添加到集合中
delegateStrategies.addAll(Arrays.asList(concurrentSessionControlStrategy,
defaultSessionAuthenticationStrategy, registerSessionStrategy));
}
else {
//值添加默认的策略
delegateStrategies.add(defaultSessionAuthenticationStrategy);
}
//生成复合会话认证策略,方便同时使用多个策略
this.sessionAuthenticationStrategy = postProcess(
new CompositeSessionAuthenticationStrategy(delegateStrategies));
return this.sessionAuthenticationStrategy;
}
private ConcurrentSessionFilter createConcurrencyFilter(H http) {
/*
*session的失效策略,如:
*1,SimpleRedirectSessionInformationExpiredStrategy 检测到过期会话时,执行重定向到固定URL
*/
SessionInformationExpiredStrategy expireStrategy = getExpiredSessionStrategy();
SessionRegistry sessionRegistry = getSessionRegistry(http);
ConcurrentSessionFilter concurrentSessionFilter;
if (expireStrategy == null) {
concurrentSessionFilter = new ConcurrentSessionFilter(sessionRegistry);
} else {
concurrentSessionFilter = new ConcurrentSessionFilter(sessionRegistry, expireStrategy);
}
LogoutConfigurer<H> logoutConfigurer = http.getConfigurer(LogoutConfigurer.class);
if (logoutConfigurer != null) {
List<LogoutHandler> logoutHandlers = logoutConfigurer.getLogoutHandlers();
if (!CollectionUtils.isEmpty(logoutHandlers)) {
concurrentSessionFilter.setLogoutHandlers(logoutHandlers);
}
}
return concurrentSessionFilter;
}
//维护SessionInformation实例的注册表
private SessionRegistry getSessionRegistry(H http) {
if (this.sessionRegistry == null) {
SessionRegistryImpl sessionRegistry = new SessionRegistryImpl();
registerDelegateApplicationListener(http, sessionRegistry);
this.sessionRegistry = sessionRegistry;
}
return this.sessionRegistry;
}
private void registerDelegateApplicationListener(H http,
ApplicationListener<?> delegate) {
ApplicationContext context = http.getSharedObject(ApplicationContext.class);
if (context == null) {
return;
}
if (context.getBeansOfType(DelegatingApplicationListener.class).isEmpty()) {
return;
}
DelegatingApplicationListener delegating = context
.getBean(DelegatingApplicationListener.class);
SmartApplicationListener smartListener = new GenericApplicationListenerAdapter(
delegate);
delegating.addListener(smartListener);
}
}
SessionRegistryImpl
/**
* org.springframework.security.core.session.SessionRegistry的默认实现,
*它侦听在Spring应用程序上下文中发布的
* org.springframework.security.core.session.SessionDestroyedEvent事件。
*
* 要使此类在web应用程序中正常工作,必须在web.xml文件中注册HttpSessionEventPublisher,以便通知此类会话已过期。
*/
public class SessionRegistryImpl implements SessionRegistry,
ApplicationListener<SessionDestroyedEvent> {
// ~ Instance fields
// ================================================================================================
protected final Log logger = LogFactory.getLog(SessionRegistryImpl.class);
/** <principal:Object,SessionIdSet> */
private final ConcurrentMap<Object, Set<String>> principals;
/** <sessionId:Object,SessionInformation> */
private final Map<String, SessionInformation> sessionIds;
// ~ Methods
// ========================================================================================================
public SessionRegistryImpl() {
this.principals = new ConcurrentHashMap<>();
this.sessionIds = new ConcurrentHashMap<>();
}
public SessionRegistryImpl(ConcurrentMap<Object, Set<String>> principals, Map<String, SessionInformation> sessionIds) {
this.principals=principals;
this.sessionIds=sessionIds;
}
public List<Object> getAllPrincipals() {
return new ArrayList<>(principals.keySet());
}
public List<SessionInformation> getAllSessions(Object principal,
boolean includeExpiredSessions) {
final Set<String> sessionsUsedByPrincipal = principals.get(principal);
if (sessionsUsedByPrincipal == null) {
return Collections.emptyList();
}
List<SessionInformation> list = new ArrayList<>(
sessionsUsedByPrincipal.size());
for (String sessionId : sessionsUsedByPrincipal) {
SessionInformation sessionInformation = getSessionInformation(sessionId);
if (sessionInformation == null) {
continue;
}
if (includeExpiredSessions || !sessionInformation.isExpired()) {
list.add(sessionInformation);
}
}
return list;
}
public SessionInformation getSessionInformation(String sessionId) {
Assert.hasText(sessionId, "SessionId required as per interface contract");
return sessionIds.get(sessionId);
}
//通知SessionDestroyedEvent 事件。
//问题:具体派发该事件的地方在哪里?
public void onApplicationEvent(SessionDestroyedEvent event) {
//过期session的ID
String sessionId = event.getId();
//移除该session的信息
removeSessionInformation(sessionId);
}
//更新最后的访问时间
public void refreshLastRequest(String sessionId) {
Assert.hasText(sessionId, "SessionId required as per interface contract");
SessionInformation info = getSessionInformation(sessionId);
if (info != null) {
info.refreshLastRequest();
}
}
public void registerNewSession(String sessionId, Object principal) {
Assert.hasText(sessionId, "SessionId required as per interface contract");
Assert.notNull(principal, "Principal required as per interface contract");
if (getSessionInformation(sessionId) != null) {
removeSessionInformation(sessionId);
}
if (logger.isDebugEnabled()) {
logger.debug("Registering session " + sessionId + ", for principal "
+ principal);
}
sessionIds.put(sessionId,
new SessionInformation(principal, sessionId, new Date()));
principals.compute(principal, (key, sessionsUsedByPrincipal) -> {
if (sessionsUsedByPrincipal == null) {
sessionsUsedByPrincipal = new CopyOnWriteArraySet<>();
}
sessionsUsedByPrincipal.add(sessionId);
if (logger.isTraceEnabled()) {
logger.trace("Sessions used by '" + principal + "' : "
+ sessionsUsedByPrincipal);
}
return sessionsUsedByPrincipal;
});
}
public void removeSessionInformation(String sessionId) {
Assert.hasText(sessionId, "SessionId required as per interface contract");
SessionInformation info = getSessionInformation(sessionId);
if (info == null) {
return;
}
if (logger.isTraceEnabled()) {
logger.debug("Removing session " + sessionId
+ " from set of registered sessions");
}
sessionIds.remove(sessionId);
principals.computeIfPresent(info.getPrincipal(), (key, sessionsUsedByPrincipal) -> {
if (logger.isDebugEnabled()) {
logger.debug("Removing session " + sessionId
+ " from principal's set of registered sessions");
}
sessionsUsedByPrincipal.remove(sessionId);
if (sessionsUsedByPrincipal.isEmpty()) {
// No need to keep object in principals Map anymore
if (logger.isDebugEnabled()) {
logger.debug("Removing principal " + info.getPrincipal()
+ " from registry");
}
sessionsUsedByPrincipal = null;
}
if (logger.isTraceEnabled()) {
logger.trace("Sessions used by '" + info.getPrincipal() + "' : "
+ sessionsUsedByPrincipal);
}
return sessionsUsedByPrincipal;
});
}
}
SessionInformation
/**
* Represents a record of a session within the Spring Security framework.
* <p>
* This is primarily used for concurrent session support.
* <p>
* Sessions have three states: active, expired, and destroyed. A session can that is
* invalidated by <code>session.invalidate()</code> or via Servlet Container management is
* considered "destroyed". An "expired" session, on the other hand, is a session that
* Spring Security wants to end because it was selected for removal for some reason
* (generally as it was the least recently used session and the maximum sessions for the
* user were reached). An "expired" session is removed as soon as possible by a
* <code>Filter</code>.
*
* @author Ben Alex
*/
public class SessionInformation implements Serializable {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
// ~ Instance fields
// ================================================================================================
private Date lastRequest;
private final Object principal;
private final String sessionId;
private boolean expired = false;
// ~ Constructors
// ===================================================================================================
public SessionInformation(Object principal, String sessionId, Date lastRequest) {
Assert.notNull(principal, "Principal required");
Assert.hasText(sessionId, "SessionId required");
Assert.notNull(lastRequest, "LastRequest required");
this.principal = principal;
this.sessionId = sessionId;
this.lastRequest = lastRequest;
}
// ~ Methods
// ========================================================================================================
public void expireNow() {
this.expired = true;
}
public Date getLastRequest() {
return lastRequest;
}
public Object getPrincipal() {
return principal;
}
public String getSessionId() {
return sessionId;
}
public boolean isExpired() {
return expired;
}
/**
* Refreshes the internal lastRequest to the current date and time.
*/
public void refreshLastRequest() {
this.lastRequest = new Date();
}
}
以上的都是初始化和装配的过程,下面再看看对请求进行拦截时候的执行过程
1,SessionManagementFilter
/**
*检测到自请求开始以来用户已通过身份验证,如果用户已通过身份验证,
*则调用配置的SessionAuthenticationStrategy执行任何与会话相关的活动,
*例如激活会话固定保护机制或检查多个并发登录。
*/
public class SessionManagementFilter extends GenericFilterBean {
// ~ Static fields/initializers
// =====================================================================================
static final String FILTER_APPLIED = "__spring_security_session_mgmt_filter_applied";
// ~ Instance fields
// ================================================================================================
private final SecurityContextRepository securityContextRepository;
private SessionAuthenticationStrategy sessionAuthenticationStrategy;
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
private InvalidSessionStrategy invalidSessionStrategy = null;
private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
public SessionManagementFilter(SecurityContextRepository securityContextRepository) {
this(securityContextRepository, new SessionFixationProtectionStrategy());
}
public SessionManagementFilter(SecurityContextRepository securityContextRepository,
SessionAuthenticationStrategy sessionStrategy) {
Assert.notNull(securityContextRepository,
"SecurityContextRepository cannot be null");
Assert.notNull(sessionStrategy, "SessionAuthenticationStrategy cannot be null");
this.securityContextRepository = securityContextRepository;
this.sessionAuthenticationStrategy = sessionStrategy;
}
//开始执行过滤器
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) {
chain.doFilter(request, response);
return;
}
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
//HttpSessionSecurityContextRepository
//NullSecurityContextRepository
if (!securityContextRepository.containsContext(request)) {
//注意:这里可是在使用Authentication哦!!!
Authentication authentication = SecurityContextHolder.getContext()
.getAuthentication();
if (authentication != null && !trustResolver.isAnonymous(authentication)) {
// 用户在当前请求期间已通过身份验证
try {
//典型的用法是确保会话存在,或者更改会话Id以防止会话固定攻击。
//那么这里用的是哪个实现类呢?
sessionAuthenticationStrategy.onAuthentication(authentication,
request, response);
}
catch (SessionAuthenticationException e) {
// The session strategy can reject the authentication
logger.debug(
"SessionAuthenticationStrategy rejected the authentication object",
e);
SecurityContextHolder.clearContext();
failureHandler.onAuthenticationFailure(request, response, e);
return;
}
// Eagerly save the security context to make it available for any possible
// re-entrant
// requests which may occur before the current request completes.
// SEC-1396.
securityContextRepository.saveContext(SecurityContextHolder.getContext(),
request, response);
}
else {
// No security context or authentication present. Check for a session
// timeout
if (request.getRequestedSessionId() != null
&& !request.isRequestedSessionIdValid()) { //如果请求的会话已经无效
if (logger.isDebugEnabled()) {
logger.debug("Requested session ID "
+ request.getRequestedSessionId() + " is invalid.");
}
if (invalidSessionStrategy != null) {
//对无效的会话进行处理
invalidSessionStrategy
.onInvalidSessionDetected(request, response);
return;
}
}
}
}
chain.doFilter(request, response);
}
}
2,ConcurrentSessionFilter
如果设置了才会执行该Filter
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
if (session != null) {
SessionInformation info = sessionRegistry.getSessionInformation(session
.getId());
if (info != null) {
if (info.isExpired()) {
// Expired - abort processing
if (logger.isDebugEnabled()) {
logger.debug("Requested session ID "
+ request.getRequestedSessionId() + " has expired.");
}
doLogout(request, response);
this.sessionInformationExpiredStrategy.onExpiredSessionDetected(new SessionInformationExpiredEvent(info, request, response));
return;
}
else {
// Non-expired - update last request date/time
sessionRegistry.refreshLastRequest(info.getSessionId());
}
}
}
chain.doFilter(request, response);
}
下面对上面场景的几个类型进行简单的梳理:
1,SessionAuthenticationStrategy
会话认证策略,默认为会话固定策略
- ChangeSessionIdAuthenticationStrategy 【默认】
- SessionFixationProtectionStrategy
- CompositeSessionAuthenticationStrategy
- ConcurrentSessionControlAuthenticationStrategy
- CsrfAuthenticationStrategy
- NullAuthenticatedSessionStrategy
- RegisterSessionAuthenticationStrategy
2,InvalidSessionStrategy
无效(失效)会话策略;
- SimpleRedirectInvalidSessionStrategy
3,SessionInformationExpiredStrategy
会话信息过期策略
- SimpleRedirectSessionInformationExpiredStrategy
- ResponseBodySessionInformationExpiredStrategy【ConcurrentSessionFilter的内部类】
4,SessionRegistry
会话注册表
- SessionRegistryImpl
5,SessionCreationPolicy【枚举】
会话创建策略.
- ALWAYS:始终创建HttpSession
- NEVER:从不创建,使用存在的HttpSession;
- IF_REQUIRED: 需要时创建HttpSession
- STATELESS:从不创建也不使用HttpSession
6,AuthenticationFailureHandler
认证失败处理器
- AuthenticationEntryPointFailureHandler
- DelegatingAuthenticationFailureHandler
- ForwardAuthenticationFailureHandler
- SimpleUrlAuthenticationFailureHandler
- ExceptionMappingAuthenticationFailureHandler
7,AuthenticationTrustResolver
对Token进行验证,主要针对:Anonymous、RememberMe
- AuthenticationTrustResolverImpl
8,SecurityContextRepository
- HttpSessionSecurityContextRepository
- NullSecurityContextRepository
9,RequestCache
- HttpSessionRequestCache
- NullRequestCache