概述
介绍
作为一个配置HttpSecurity
的SecurityConfigurer
,SessionManagementConfigurer
作了如下配置工作 :
- 为
HttpSecurity
提供如下过滤器(Filter
)SessionManagementFilter
使用者可对该过滤器所需属性进行设置
ConcurrentSessionFilter
- 仅在限定最大会话数量时创建该过滤器
- 使用者可对该过滤器所需属性进行设置
- 为
HttpSecurity
设置如下共享对象RequestCache
仅在共享对象中不存在此类对象时创建并设置为共享对象
仅在无状态模式下设置共享对象,实现类使用NullRequestCache
(也就是不使用request
缓存)SecurityContextRepository
仅在共享对象中不存在此类对象时创建并设置为共享对象
无状态模式下设置的是NullSecurityContextRepository
,否则是HttpSessionSecurityContextRepository
SessionAuthenticationStrategy
InvalidSessionStrategy
通过SessionManagementConfigurer
可以做如下方面的安全配置:
-
#invalidSessionUrl
设置
session id
无效时的跳转URL
。如果设置了该属性,浏览器端提供了无效的session id
时,服务器端会将其跳转到所设置的URL
。 -
#invalidSessionStrategy
设置
session id
无效时要应用的策略InvalidSessionStrategy
。如果设置了该属性,浏览器端提供了无效的session id
时,服务器端会调用该策略对象。通常情况下,这里也会是一个跳转策略对象
SimpleRedirectInvalidSessionStrategy
。因为InvalidSessionStrategy
是一个接口,而Spring Security
内置地对该接口仅提供了一个实现就是SimpleRedirectInvalidSessionStrategy
。
#invalidSessionStrategy和
#invalidSessionUrl都被调用时,#invalidSessionStrategy
会生效; -
#sessionAuthenticationErrorUrl
定义
SessionAuthenticationStrategy
抛出异常时要跳转的URL
。如果未设置该属性,SessionAuthenticationStrategy
抛出异常时,会返回402给客户端。注意在基于表单的登录失败时,该属性并不应用。因为此时表单认证失败
URL
会先被跳转。 -
#sessionAuthenticationFailureHandler
定义
SessionAuthenticationStrategy
抛出异常时要应用的认证失败处理器AuthenticationFailureHandler
。如果未设置该属性,SessionAuthenticationStrategy
抛出异常时,会返回402给客户端。注意在基于表单的登录失败时,该属性并不应用。因为此时表单认证失败
URL
会先被跳转。如果
#sessionAuthenticationErrorUrl
和#sessionAuthenticationFailureHandler
都被调用,#sessionAuthenticationFailureHandler
会生效; -
#enableSessionUrlRewriting
调用该方法设置属性
enableSessionUrlRewriting
.如果enableSessionUrlRewriting
属性被设置为true
,使用HttpServletResponse#encodeRedirectURL(String)
/HttpServletResponse#encodeURL(String)
时,允许将HTTP session
信息重写到URL
中。该方法对应的属性enableSessionUrlRewriting
缺省为false
,不允许Http session
重写到URL
。 -
#sessionCreationPolicy
设置会话创建策略
SessionCreationPolicy
。如果不设置,则会尝试使用公共对象中设置的SessionCreationPolicy
。如果公共对象中也没有设置会话创建策略,则使用缺省的会话创建策略SessionCreationPolicy.IF_REQUIRED
。 -
#sessionAuthenticationStrategy
允许设置一个会话认证策略。如果不设置,会使用缺省值。缺省值是
SessionFixationProtectionStrategy(针对Servlet 3.1)
/ChangeSessionIdAuthenticationStrategy(针对Servlet 3.1+)
。 -
#maximumSessions
设置每个用户的最大并发会话数量。此方法返回一个
ConcurrencyControlConfigurer
,这也是一个安全配置器,设置每个用户会话数量超出单用户最大会话并发数时如何处理。ConcurrencyControlConfigurer
的配置能力如下#expiredUrl
设置一个
URL
。如果某用户达到单用户最大会话并发数后再次请求新会话,则将最老的会话超时并将其跳转到该URL
。#expiredSessionStrategy
设置一个会话信息超时策略对象
SessionInformationExpiredStrategy
。如果某用户达到单用户最大会话并发数后再次请求新会话,则调用该策略超时哪个会话以及进行什么样的超时处理。
如果#expiredUrl
和#expiredSessionStrategy
都被调用,#expiredSessionStrategy
生效。#maxSessionsPreventsLogin
设置属性
maxSessionsPreventsLogin
.如果设置为true
,则某用户达到单用户最大会话并发数后再次请求登录时会被拒绝登录。
缺省情况下maxSessionsPreventsLogin
为false
。则某用户达到单用户最大会话并发数后再次请求登录时,其最老会话会被超时并被重定向到#expiredUrl
所设置的URL
(或者被#expiredSessionStrategy
所设置策略处理)。#sessionRegistry
设置所要使用的
SessionRegistry
,不设置时的缺省值为一个SessionRegistryImpl
。
-
#sessionFixation
此方法返回一个
SessionFixationConfigurer
,这也是一个安全配置器,专门对Session Fixcation
保护机制做出设置。SessionFixationConfigurer
的配置能力如下#newSession
设置固定会话攻击保护策略为
SessionFixationProtectionStrategy
,该策略会在用户会话认证成功时创建新的会话,但不会复制旧会话的属性。#migrateSession
设置固定会话攻击保护策略为
SessionFixationProtectionStrategy
,该策略会在用户会话认证成功时创建新的会话,并且复制旧会话的属性。#changeSessionId
设置固定会话攻击保护策略为
ChangeSessionIdAuthenticationStrategy
,仅针对Servlet 3.1+
,在用户会话认证成功时调用Servlet 3.1
方法HttpServletRequest#changeSessionId()
变更会话ID
并保留所有会话属性。在Servlet 3.0
或者更早版本中使用该策略会触发异常IllegalStateException
。#none
设置固定会话攻击保护策略为
NullAuthenticatedSessionStrategy
。这种策略其实是关闭Spring Security
的固定会话攻击保护策略。该方案多用在应用已经启用了其他的固定会话攻击保护策略的情况下,比如使用了应用服务器端固定会话攻击保护策略。如果没有采用其他固定会话攻击保护策略,建议不要使用此选项。
继承关系
使用
// HttpSecurity 类代码片段
public SessionManagementConfigurer<HttpSecurity> sessionManagement() throws Exception {
return getOrApply(new SessionManagementConfigurer<>());
}
源代码
源代码版本 Spring Security Config 5.1.4.RELEASE
package org.springframework.security.config.annotation.web.configurers;
// 忽略 imports
public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<SessionManagementConfigurer<H>, H> {
private final SessionAuthenticationStrategy DEFAULT_SESSION_FIXATION_STRATEGY =
createDefaultSessionFixationProtectionStrategy();
// 会话认证策略,初始化为 DEFAULT_SESSION_FIXATION_STRATEGY
private SessionAuthenticationStrategy sessionFixationAuthenticationStrategy =
this.DEFAULT_SESSION_FIXATION_STRATEGY;
private SessionAuthenticationStrategy sessionAuthenticationStrategy;
// 用于记录外部指定的会话认证策略
private SessionAuthenticationStrategy providedSessionAuthenticationStrategy;
// 用户提供了无效会话id时的处理策略
private InvalidSessionStrategy invalidSessionStrategy;
// 会话超时处理策略
private SessionInformationExpiredStrategy expiredSessionStrategy;
private List<SessionAuthenticationStrategy> sessionAuthenticationStrategies = new ArrayList<>();
private SessionRegistry sessionRegistry;
// 单用户会话最大并发数,缺省不设置,表示不限制
private Integer maximumSessions;
// 用户会话超时时的跳转URL
private String expiredUrl;
// true - 某用户会话数量超过单用户会话最大并发数时禁止更多登录
// 缺省为 false
private boolean maxSessionsPreventsLogin;
private SessionCreationPolicy sessionPolicy;
private boolean enableSessionUrlRewriting;
// 用户提供了无效会话id时的跳转url
private String invalidSessionUrl;
private String sessionAuthenticationErrorUrl;
private AuthenticationFailureHandler sessionAuthenticationFailureHandler;
/**
* Creates a new instance
* @see HttpSecurity#sessionManagement()
*/
public SessionManagementConfigurer() {
}
/**
* Setting this attribute will inject the SessionManagementFilter with a
* SimpleRedirectInvalidSessionStrategy configured with the attribute value.
* When an invalid session ID is submitted, the strategy will be invoked, redirecting
* to the configured URL.
*
* 设置一个无效会话url。
* 设置该属性后,会在目标 SessionManagementFilter 上注入一个
* SimpleRedirectInvalidSessionStrategy 策略对象,当浏览器端提供一个无效的会话ID时,
* 该策略对象会被调用,跳转浏览器到所指定的URL : invalidSessionUrl
*
* @param invalidSessionUrl the URL to redirect to when an invalid session is detected
* @return the SessionManagementConfigurer for further customization
*/
public SessionManagementConfigurer<H> invalidSessionUrl(String invalidSessionUrl) {
this.invalidSessionUrl = invalidSessionUrl;
return this;
}
/**
* Setting this attribute will inject the provided invalidSessionStrategy into the
* SessionManagementFilter. When an invalid session ID is submitted, the
* strategy will be invoked, redirecting to the configured URL.
* @param invalidSessionStrategy the strategy to use when an invalid session ID is
* submitted.
* @return the SessionManagementConfigurer for further customization
*/
public SessionManagementConfigurer<H> invalidSessionStrategy(
InvalidSessionStrategy invalidSessionStrategy) {
Assert.notNull(invalidSessionStrategy, "invalidSessionStrategy");
this.invalidSessionStrategy = invalidSessionStrategy;
return this;
}
/**
* Defines the URL of the error page which should be shown when the
* SessionAuthenticationStrategy raises an exception. If not set, an unauthorized
* (402) error code will be returned to the client. Note that this attribute doesn't
* apply if the error occurs during a form-based login, where the URL for
* authentication failure will take precedence.
*
* @param sessionAuthenticationErrorUrl the URL to redirect to
* @return the SessionManagementConfigurer for further customization
*/
public SessionManagementConfigurer<H> sessionAuthenticationErrorUrl(
String sessionAuthenticationErrorUrl) {
this.sessionAuthenticationErrorUrl = sessionAuthenticationErrorUrl;
return this;
}
/**
* Defines the AuthenticationFailureHandler which will be used when the
* SessionAuthenticationStrategy raises an exception. If not set, an unauthorized
* (402) error code will be returned to the client. Note that this attribute doesn't
* apply if the error occurs during a form-based login, where the URL for
* authentication failure will take precedence.
*
* @param sessionAuthenticationFailureHandler the handler to use
* @return the SessionManagementConfigurer for further customization
*/
public SessionManagementConfigurer<H> sessionAuthenticationFailureHandler(
AuthenticationFailureHandler sessionAuthenticationFailureHandler) {
this.sessionAuthenticationFailureHandler = sessionAuthenticationFailureHandler;
return this;
}
/**
* If set to true, allows HTTP sessions to be rewritten in the URLs when using
* HttpServletResponse#encodeRedirectURL(String) or
* HttpServletResponse#encodeURL(String), otherwise disallows HTTP sessions to
* be included in the URL. This prevents leaking information to external domains.
*
* @param enableSessionUrlRewriting true if should allow the JSESSIONID to be
* rewritten into the URLs, else false (default)
* @return the SessionManagementConfigurer for further customization
* @see HttpSessionSecurityContextRepository#setDisableUrlRewriting(boolean)
*/
public SessionManagementConfigurer<H> enableSessionUrlRewriting(
boolean enableSessionUrlRewriting) {
this.enableSessionUrlRewriting = enableSessionUrlRewriting;
return this;
}
/**
* Allows specifying the SessionCreationPolicy
* @param sessionCreationPolicy the SessionCreationPolicy to use. Cannot be
* null.
* @return the SessionManagementConfigurer for further customizations
* @see SessionCreationPolicy
* @throws IllegalArgumentException if SessionCreationPolicy is null.
*/
public SessionManagementConfigurer<H> sessionCreationPolicy(
SessionCreationPolicy sessionCreationPolicy) {
Assert.notNull(sessionCreationPolicy, "sessionCreationPolicy cannot be null");
this.sessionPolicy = sessionCreationPolicy;
return this;
}
/**
* Allows explicitly specifying the SessionAuthenticationStrategy.
* The default is to use SessionFixationProtectionStrategy for Servlet 3.1 or
* ChangeSessionIdAuthenticationStrategy for Servlet 3.1+.
* If restricting the maximum number of sessions is configured, then
* CompositeSessionAuthenticationStrategy delegating to
* ConcurrentSessionControlAuthenticationStrategy,
* the default OR supplied SessionAuthenticationStrategy and
* RegisterSessionAuthenticationStrategy.
*
*
* NOTE: Supplying a custom SessionAuthenticationStrategy will override the
* default session fixation strategy.
*
* @param sessionAuthenticationStrategy
* @return the SessionManagementConfigurer for further customizations
*/
public SessionManagementConfigurer<H> sessionAuthenticationStrategy(
SessionAuthenticationStrategy sessionAuthenticationStrategy) {
this.providedSessionAuthenticationStrategy = sessionAuthenticationStrategy;
return this;
}
/**
* Adds an additional SessionAuthenticationStrategy to be used within the
* CompositeSessionAuthenticationStrategy.
*
* @param sessionAuthenticationStrategy
* @return the SessionManagementConfigurer for further customizations
*/
SessionManagementConfigurer<H> addSessionAuthenticationStrategy(
SessionAuthenticationStrategy sessionAuthenticationStrategy) {
this.sessionAuthenticationStrategies.add(sessionAuthenticationStrategy);
return this;
}
public SessionFixationConfigurer sessionFixation() {
return new SessionFixationConfigurer();
}
/**
* Controls the maximum number of sessions for a user. The default is to allow any
* number of users.
* @param maximumSessions the maximum number of sessions for a user
* @return the SessionManagementConfigurer for further customizations
*/
public ConcurrencyControlConfigurer maximumSessions(int maximumSessions) {
this.maximumSessions = maximumSessions;
return new ConcurrencyControlConfigurer();
}
/**
* Invokes #postProcess(Object) and sets the
* SessionAuthenticationStrategy for session fixation.
* @param sessionFixationAuthenticationStrategy
*/
private void setSessionFixationAuthenticationStrategy(
SessionAuthenticationStrategy sessionFixationAuthenticationStrategy) {
this.sessionFixationAuthenticationStrategy = postProcess(
sessionFixationAuthenticationStrategy);
}
/**
* Allows configuring SessionFixation protection
*
* @author Rob Winch
*/
public final class SessionFixationConfigurer {
/**
* Specifies that a new session should be created, but the session attributes from
* the original HttpSession should not be retained.
*
* @return the SessionManagementConfigurer for further customizations
*/
public SessionManagementConfigurer<H> newSession() {
SessionFixationProtectionStrategy sessionFixationProtectionStrategy =
new SessionFixationProtectionStrategy();
sessionFixationProtectionStrategy.setMigrateSessionAttributes(false);
setSessionFixationAuthenticationStrategy(sessionFixationProtectionStrategy);
return SessionManagementConfigurer.this;
}
/**
* Specifies that a new session should be created and the session attributes from
* the original HttpSession should be retained.
*
* @return the SessionManagementConfigurer for further customizations
*/
public SessionManagementConfigurer<H> migrateSession() {
setSessionFixationAuthenticationStrategy(
new SessionFixationProtectionStrategy());
return SessionManagementConfigurer.this;
}
/**
* Specifies that the Servlet container-provided session fixation protection
* should be used. When a session authenticates, the Servlet 3.1 method
* HttpServletRequest#changeSessionId() is called to change the session ID
* and retain all session attributes. Using this option in a Servlet 3.0 or older
* container results in an IllegalStateException.
*
* @return the SessionManagementConfigurer for further customizations
* @throws IllegalStateException if the container is not Servlet 3.1 or newer.
*/
public SessionManagementConfigurer<H> changeSessionId() {
setSessionFixationAuthenticationStrategy(
new ChangeSessionIdAuthenticationStrategy());
return SessionManagementConfigurer.this;
}
/**
* Specifies that no session fixation protection should be enabled. This may be
* useful when utilizing other mechanisms for protecting against session fixation.
* For example, if application container session fixation protection is already in
* use. Otherwise, this option is not recommended.
*
* @return the SessionManagementConfigurer for further customizations
*/
public SessionManagementConfigurer<H> none() {
setSessionFixationAuthenticationStrategy(
new NullAuthenticatedSessionStrategy());
return SessionManagementConfigurer.this;
}
}
/**
* Allows configuring controlling of multiple sessions.
*
* @author Rob Winch
*/
public final class ConcurrencyControlConfigurer {
/**
* The URL to redirect to if a user tries to access a resource and their session
* has been expired due to too many sessions for the current user. The default is
* to write a simple error message to the response.
*
* @param expiredUrl the URL to redirect to
* @return the ConcurrencyControlConfigurer for further customizations
*/
public ConcurrencyControlConfigurer expiredUrl(String expiredUrl) {
SessionManagementConfigurer.this.expiredUrl = expiredUrl;
return this;
}
public ConcurrencyControlConfigurer expiredSessionStrategy(
SessionInformationExpiredStrategy expiredSessionStrategy) {
SessionManagementConfigurer.this.expiredSessionStrategy = expiredSessionStrategy;
return this;
}
/**
* If true, prevents a user from authenticating when the
* #maximumSessions(int) has been reached. Otherwise (default), the user
* who authenticates is allowed access and an existing user's session is expired.
* The user's who's session is forcibly expired is sent to
* #expiredUrl(String). The advantage of this approach is if a user
* accidentally does not log out, there is no need for an administrator to
* intervene or wait till their session expires.
*
* @param maxSessionsPreventsLogin true to have an error at time of
* authentication, else false (default)
* @return the ConcurrencyControlConfigurer for further customizations
*/
public ConcurrencyControlConfigurer maxSessionsPreventsLogin(
boolean maxSessionsPreventsLogin) {
SessionManagementConfigurer.this.maxSessionsPreventsLogin = maxSessionsPreventsLogin;
return this;
}
/**
* Controls the SessionRegistry implementation used. The default is
* SessionRegistryImpl which is an in memory implementation.
*
* @param sessionRegistry the SessionRegistry to use
* @return the ConcurrencyControlConfigurer for further customizations
*/
public ConcurrencyControlConfigurer sessionRegistry(
SessionRegistry sessionRegistry) {
SessionManagementConfigurer.this.sessionRegistry = sessionRegistry;
return this;
}
/**
* Used to chain back to the SessionManagementConfigurer
*
* @return the SessionManagementConfigurer for further customizations
*/
public SessionManagementConfigurer<H> and() {
return SessionManagementConfigurer.this;
}
private ConcurrencyControlConfigurer() {
}
}
@Override
public void init(H http) throws Exception {
// 如果 HTTPSecurity 共享对象 SecurityContextRepository 不存在,
// 则根据情况创建并添加为 HTTPSecurity 共享对象
SecurityContextRepository securityContextRepository = http
.getSharedObject(SecurityContextRepository.class);
boolean stateless = isStateless();
if (securityContextRepository == null) {
if (stateless) {
http.setSharedObject(SecurityContextRepository.class,
new NullSecurityContextRepository());
}
else {
HttpSessionSecurityContextRepository httpSecurityRepository =
new HttpSessionSecurityContextRepository();
httpSecurityRepository
.setDisableUrlRewriting(!this.enableSessionUrlRewriting);
httpSecurityRepository.setAllowSessionCreation(isAllowSessionCreation());
AuthenticationTrustResolver trustResolver = http
.getSharedObject(AuthenticationTrustResolver.class);
if (trustResolver != null) {
httpSecurityRepository.setTrustResolver(trustResolver);
}
http.setSharedObject(SecurityContextRepository.class,
httpSecurityRepository);
}
}
// 如果 HTTPSecurity 共享对象 RequestCache 不存在,则根据情况创建并添加为 HTTPSecurity 共享对象
RequestCache requestCache = http.getSharedObject(RequestCache.class);
if (requestCache == null) {
if (stateless) {
http.setSharedObject(RequestCache.class, new NullRequestCache());
}
}
// 根据情况创建 RequestCache 并添加为 HTTPSecurity 共享对象
http.setSharedObject(SessionAuthenticationStrategy.class,
getSessionAuthenticationStrategy(http));
// 根据情况创建 InvalidSessionStrategy 并添加为 HTTPSecurity 共享对象
http.setSharedObject(InvalidSessionStrategy.class, getInvalidSessionStrategy());
}
@Override
public void configure(H http) throws Exception {
SecurityContextRepository securityContextRepository = http
.getSharedObject(SecurityContextRepository.class);
// 创建 SessionManagementFilter
SessionManagementFilter sessionManagementFilter = new SessionManagementFilter(
securityContextRepository, getSessionAuthenticationStrategy(http));
if (this.sessionAuthenticationErrorUrl != null) {
sessionManagementFilter.setAuthenticationFailureHandler(
new SimpleUrlAuthenticationFailureHandler(
this.sessionAuthenticationErrorUrl));
}
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);
// 添加 SessionManagementFilter 到 HttpSecurity
http.addFilter(sessionManagementFilter);
// 如果设定了 maximumSessions (标准:不为null),则创建 ConcurrentSessionFilter
if (isConcurrentSessionControlEnabled()) {
ConcurrentSessionFilter concurrentSessionFilter = createConccurencyFilter(http);
concurrentSessionFilter = postProcess(concurrentSessionFilter);
// 添加 ConcurrentSessionFilter 到 HttpSecurity
http.addFilter(concurrentSessionFilter);
}
}
private ConcurrentSessionFilter createConccurencyFilter(H http) {
SessionInformationExpiredStrategy expireStrategy = getExpiredSessionStrategy();
SessionRegistry sessionRegistry = getSessionRegistry(http);
if (expireStrategy == null) {
return new ConcurrentSessionFilter(sessionRegistry);
}
return new ConcurrentSessionFilter(sessionRegistry, expireStrategy);
}
/**
* Gets the InvalidSessionStrategy to use. If null and
* #invalidSessionUrl is not null defaults to
* SimpleRedirectInvalidSessionStrategy.
*
* @return the InvalidSessionStrategy to use
*/
InvalidSessionStrategy getInvalidSessionStrategy() {
if (this.invalidSessionStrategy != null) {
return this.invalidSessionStrategy;
}
if (this.invalidSessionUrl != null) {
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;
}
SessionInformationExpiredStrategy getExpiredSessionStrategy() {
if (this.expiredSessionStrategy != null) {
return this.expiredSessionStrategy;
}
if (this.expiredUrl == null) {
return null;
}
if (this.expiredSessionStrategy == null) {
this.expiredSessionStrategy = new SimpleRedirectSessionInformationExpiredStrategy(
this.expiredUrl);
}
return this.expiredSessionStrategy;
}
AuthenticationFailureHandler getSessionAuthenticationFailureHandler() {
if (this.sessionAuthenticationFailureHandler != null) {
return this.sessionAuthenticationFailureHandler;
}
if (this.sessionAuthenticationErrorUrl == null) {
return null;
}
if (this.sessionAuthenticationFailureHandler == null) {
this.sessionAuthenticationFailureHandler = new SimpleUrlAuthenticationFailureHandler(
this.sessionAuthenticationErrorUrl);
}
return this.sessionAuthenticationFailureHandler;
}
/**
* Gets the SessionCreationPolicy. Can not be null.
* 检查自己或者HttpSecurity构建器共享对象中的 SessionCreationPolicy 设置,
* 如果有则返回直接使用,
* 如果没有,返回 IF_REQUIRED
* @return the SessionCreationPolicy
*/
SessionCreationPolicy getSessionCreationPolicy() {
if (this.sessionPolicy != null) {
return this.sessionPolicy;
}
SessionCreationPolicy sessionPolicy =
getBuilder().getSharedObject(SessionCreationPolicy.class);
return sessionPolicy == null ?
SessionCreationPolicy.IF_REQUIRED : sessionPolicy;
}
/**
* Returns true if the SessionCreationPolicy allows session creation, else
* false
* 是否被允许创建会话,根据所设置的 SessionCreationPolicy 判断,
* 如果所设置的 SessionCreationPolicy 为 ALWAYS 或者 IF_REQUIRED,
* 则允许创建会话
* @return true if the SessionCreationPolicy allows session creation
*/
private boolean isAllowSessionCreation() {
SessionCreationPolicy sessionPolicy = getSessionCreationPolicy();
return SessionCreationPolicy.ALWAYS == sessionPolicy
|| SessionCreationPolicy.IF_REQUIRED == sessionPolicy;
}
/**
* Returns true if the SessionCreationPolicy is stateless
* 如果配置指定的会话创建策略为无状态 STATELESS,则返回 true
* @return
*/
private boolean isStateless() {
SessionCreationPolicy sessionPolicy = getSessionCreationPolicy();
return SessionCreationPolicy.STATELESS == sessionPolicy;
}
/**
* Gets the customized SessionAuthenticationStrategy if
* #sessionAuthenticationStrategy(SessionAuthenticationStrategy) was
* specified. Otherwise creates a default SessionAuthenticationStrategy.
*
* @return the SessionAuthenticationStrateg} to use
*/
private SessionAuthenticationStrategy getSessionAuthenticationStrategy(H http) {
if (this.sessionAuthenticationStrategy != null) {
return this.sessionAuthenticationStrategy;
}
List<SessionAuthenticationStrategy> delegateStrategies = this.sessionAuthenticationStrategies;
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;
}
if (isConcurrentSessionControlEnabled()) {
SessionRegistry sessionRegistry = getSessionRegistry(http);
ConcurrentSessionControlAuthenticationStrategy concurrentSessionControlStrategy =
new ConcurrentSessionControlAuthenticationStrategy(
sessionRegistry);
concurrentSessionControlStrategy.setMaximumSessions(this.maximumSessions);
concurrentSessionControlStrategy
.setExceptionIfMaximumExceeded(this.maxSessionsPreventsLogin);
concurrentSessionControlStrategy = postProcess(
concurrentSessionControlStrategy);
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;
}
// 如果 this.sessionRegistry 尚未创建,则使用 SessionRegistryImpl 创建,
// 并包装为一个事件监听器 GenericApplicationListenerAdapter 注册到 httpSecurity http
// 共享对象应用上下文中的 DelegatingApplicationListener bean
private SessionRegistry getSessionRegistry(H http) {
if (this.sessionRegistry == null) {
SessionRegistryImpl sessionRegistry = new SessionRegistryImpl();
registerDelegateApplicationListener(http, sessionRegistry);
this.sessionRegistry = sessionRegistry;
}
return this.sessionRegistry;
}
// 将 delegate 包装为一个事件监听器 GenericApplicationListenerAdapter 注册到 httpSecurity http
// 共享对象应用上下文中的 DelegatingApplicationListener bean
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);
}
/**
* Returns true if the number of concurrent sessions per user should be restricted.
* @return
*/
private boolean isConcurrentSessionControlEnabled() {
return this.maximumSessions != null;
}
/**
* Creates the default SessionAuthenticationStrategy for session fixation
* @return the default SessionAuthenticationStrategy for session fixation
*/
private static SessionAuthenticationStrategy createDefaultSessionFixationProtectionStrategy() {
try {
return new ChangeSessionIdAuthenticationStrategy();
}
catch (IllegalStateException e) {
return new SessionFixationProtectionStrategy();
}
}
}