Spring Security Config : HttpSecurity安全配置器 SessionManagementConfigurer

本文围绕Spring Security Config 5.1.4.RELEASE版本的配置展开。介绍了其作为配置所做的工作,包括设置过滤器、共享对象等。还阐述了多方面的安全配置,如无效会话跳转、异常处理、会话创建与认证策略、并发会话数量处理及固定会话攻击保护策略等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

介绍

作为一个配置HttpSecuritySecurityConfigurer,SessionManagementConfigurer作了如下配置工作 :

  • HttpSecurity提供如下过滤器(Filter)
    • SessionManagementFilter

      使用者可对该过滤器所需属性进行设置

    • ConcurrentSessionFilter
      1. 仅在限定最大会话数量时创建该过滤器
      2. 使用者可对该过滤器所需属性进行设置
  • 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,则某用户达到单用户最大会话并发数后再次请求登录时会被拒绝登录。
        缺省情况下maxSessionsPreventsLoginfalse。则某用户达到单用户最大会话并发数后再次请求登录时,其最老会话会被超时并被重定向到#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的固定会话攻击保护策略。该方案多用在应用已经启用了其他的固定会话攻击保护策略的情况下,比如使用了应用服务器端固定会话攻击保护策略。如果没有采用其他固定会话攻击保护策略,建议不要使用此选项。

继承关系

SessionManagementConfigurer

使用

    // 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();
		}
	}
}

参考文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值