Spring Security : HTTP请求安全构建器 HttpSecurity

HttpSecuritySpring Security Config用于配置http请求安全控制的安全构建器(类似于Spring Security XML配置中的http命名空间配置部分),它的构建目标是一个SecurityFilterChain,实现类使用DefaultSecurityFilterChain。该目标SecurityFilterChain最终会被Spring Security的安全过滤器FilterChainProxy所持有和应用于相应的http请求的安全控制。

HttpSecurity缺省情况下应用到所有的请求,不过也可通过使用其方法#requestMatcher(RequestMatcher)(或者其他类似的手段)限制它仅应用到某些请求上。

安全构建器HttpSecurityWebSecurity的区别是 :

  1. WebSecurity不仅通过HttpSecurity定义某些请求的安全控制,也通过其他方式定义其他某些请求可以忽略安全控制;
  2. HttpSecurity仅用于定义需要安全控制的请求(当然HttpSecurity也可以指定某些请求不需要安全控制);
  3. 可以认为HttpSecurityWebSecurity的一部分,WebSecurity是包含HttpSecurity的更大的一个概念;

    注意 : 这里是从语义上讲,而不是从实现层面的表示形式上讲;

  4. 构建目标不同
    1. WebSecurity构建目标是整个Spring Security安全过滤器FilterChainProxy,
    2. HttpSecurity的构建目标仅仅是FilterChainProxy中的一个SecurityFilterChain

一个HttpSecurity 使用的例子 :

 @Configuration
 @EnableWebSecurity
 public class FormLoginSecurityConfig extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
                http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin();
        }

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
                auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
        }
 } 

源代码

源代码版本 Spring Security Config 5.1.4.RELEASE

package org.springframework.security.config.annotation.web.builders;

// 省略 imports 行

/**
 *
 * @author Rob Winch
 * @author Joe Grandja
 * @since 3.2
 * @see EnableWebSecurity
 */
public final class HttpSecurity extends
		AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
		implements SecurityBuilder<DefaultSecurityFilterChain>,
		HttpSecurityBuilder<HttpSecurity> {
	private final RequestMatcherConfigurer requestMatcherConfigurer;
	private List<Filter> filters = new ArrayList<>();
	private RequestMatcher requestMatcher = AnyRequestMatcher.INSTANCE;
	private FilterComparator comparator = new FilterComparator();

	/**
	 * Creates a new instance
	 * @param objectPostProcessor the ObjectPostProcessor that should be used
	 * @param authenticationBuilder the AuthenticationManagerBuilder to use for
	 * additional updates
	 * @param sharedObjects the shared Objects to initialize the HttpSecurity with
	 * @see WebSecurityConfiguration
	 */
	@SuppressWarnings("unchecked")
	public HttpSecurity(ObjectPostProcessor<Object> objectPostProcessor,
			AuthenticationManagerBuilder authenticationBuilder,
			Map<Class<? extends Object>, Object> sharedObjects) {
		super(objectPostProcessor);
		Assert.notNull(authenticationBuilder, "authenticationBuilder cannot be null");
		setSharedObject(AuthenticationManagerBuilder.class, authenticationBuilder);
		for (Map.Entry<Class<? extends Object>, Object> entry : sharedObjects
				.entrySet()) {
			setSharedObject((Class<Object>) entry.getKey(), entry.getValue());
		}
		ApplicationContext context = (ApplicationContext) sharedObjects
				.get(ApplicationContext.class);
		this.requestMatcherConfigurer = new RequestMatcherConfigurer(context);
	}

	private ApplicationContext getContext() {
		return getSharedObject(ApplicationContext.class);
	}

	/**
	 * Allows configuring OpenID based authentication.
	 *
	 *
	 * @return the OpenIDLoginConfigurer for further customizations.
	 *
	 * @throws Exception
	 * @see OpenIDLoginConfigurer
	 */
	public OpenIDLoginConfigurer<HttpSecurity> openidLogin() throws Exception {
		return getOrApply(new OpenIDLoginConfigurer<>());
	}

	/**
	 * Adds the Security headers to the response. This is activated by default when using
	 * WebSecurityConfigurerAdapter's default constructor. Accepting the
	 * default provided by WebSecurityConfigurerAdapter or only invoking
	 * #headers() without invoking additional methods on it
     */
	public HeadersConfigurer<HttpSecurity> headers() throws Exception {
		return getOrApply(new HeadersConfigurer<>());
	}

	/**
	 * Adds a CorsFilter to be used. If a bean by the name of corsFilter is
	 * provided, that CorsFilter is used. Else if corsConfigurationSource is
	 * defined, then that CorsConfiguration is used. Otherwise, if Spring MVC is
	 * on the classpath a HandlerMappingIntrospector is used.
	 *
	 * @return the CorsConfigurer for customizations
	 * @throws Exception
	 */
	public CorsConfigurer<HttpSecurity> cors() throws Exception {
		return getOrApply(new CorsConfigurer<>());
	}

	/**
	 * Allows configuring of Session Management.
	 *
	 * When using SessionManagementConfigurer#maximumSessions(int), do not forget
	 * to configure HttpSessionEventPublisher for the application to ensure that
	 * expired sessions are cleaned up.
	 *
	 *
	 * @return the SessionManagementConfigurer for further customizations
	 * @throws Exception
	 */
	public SessionManagementConfigurer<HttpSecurity> sessionManagement() throws Exception {
		return getOrApply(new SessionManagementConfigurer<>());
	}

	/**
	 * Allows configuring a PortMapper that is available from
	 * HttpSecurity#getSharedObject(Class). Other provided
	 * SecurityConfigurer objects use this configured PortMapper as a
	 * default PortMapper when redirecting from HTTP to HTTPS or from HTTPS to
	 * HTTP (for example when used in combination with #requiresChannel(). By
	 * default Spring Security uses a PortMapperImpl which maps the HTTP port 8080
	 * to the HTTPS port 8443 and the HTTP port of 80 to the HTTPS port of 443.
	 *
	 *
	 * @return the PortMapperConfigurer for further customizations
	 * @throws Exception
	 * @see #requiresChannel()
	 */
	public PortMapperConfigurer<HttpSecurity> portMapper() throws Exception {
		return getOrApply(new PortMapperConfigurer<>());
	}

	/**
	 * Configures container based pre authentication. In this case, authentication
	 * is managed by the Servlet Container.
	 *
	 *
	 * @return the JeeConfigurer for further customizations
	 * @throws Exception
	 */
	public JeeConfigurer<HttpSecurity> jee() throws Exception {
		return getOrApply(new JeeConfigurer<>());
	}

	/**
	 * Configures X509 based pre authentication.
	 *
	 *
	 * @return the X509Configurer for further customizations
	 * @throws Exception
	 */
	public X509Configurer<HttpSecurity> x509() throws Exception {
		return getOrApply(new X509Configurer<>());
	}

	/**
	 * Allows configuring of Remember Me authentication.
	 *
	 *
	 * @return the RememberMeConfigurer for further customizations
	 * @throws Exception
	 */
	public RememberMeConfigurer<HttpSecurity> rememberMe() throws Exception {
		return getOrApply(new RememberMeConfigurer<>());
	}

	/**
	 * Allows restricting access based upon the HttpServletRequest using
	 *
	 *
	 *
	 * @see #requestMatcher(RequestMatcher)
	 *
	 * @return the ExpressionUrlAuthorizationConfigurer for further customizations
	 * @throws Exception
	 */
	public ExpressionUrlAuthorizationConfigurer<HttpSecurity>.
				ExpressionInterceptUrlRegistry authorizeRequests()
			throws Exception {
		ApplicationContext context = getContext();
		return getOrApply(new ExpressionUrlAuthorizationConfigurer<>(context))
				.getRegistry();
	}

	/**
	 * Allows configuring the Request Cache. For example, a protected page (/protected)
	 * may be requested prior to authentication. The application will redirect the user to
	 * a login page. After authentication, Spring Security will redirect the user to the
	 * originally requested protected page (/protected). This is automatically applied
	 * when using WebSecurityConfigurerAdapter.
	 *
	 * @return the RequestCacheConfigurer for further customizations
	 * @throws Exception
	 */
	public RequestCacheConfigurer<HttpSecurity> requestCache() throws Exception {
		return getOrApply(new RequestCacheConfigurer<>());
	}

	/**
	 * Allows configuring exception handling. This is automatically applied when using
	 * WebSecurityConfigurerAdapter.
	 *
	 * @return the ExceptionHandlingConfigurer for further customizations
	 * @throws Exception
	 */
	public ExceptionHandlingConfigurer<HttpSecurity> exceptionHandling() throws Exception {
		return getOrApply(new ExceptionHandlingConfigurer<>());
	}

	/**
	 * Sets up management of the SecurityContext on the
	 * SecurityContextHolder between HttpServletRequest's. This is
	 * automatically applied when using WebSecurityConfigurerAdapter.
	 *
	 * @return the SecurityContextConfigurer for further customizations
	 * @throws Exception
	 */
	public SecurityContextConfigurer<HttpSecurity> securityContext() throws Exception {
		return getOrApply(new SecurityContextConfigurer<>());
	}

	/**
	 * Integrates the HttpServletRequest methods with the values found on the
	 * SecurityContext. This is automatically applied when using
	 * WebSecurityConfigurerAdapter.
	 *
	 * @return the ServletApiConfigurer for further customizations
	 * @throws Exception
	 */
	public ServletApiConfigurer<HttpSecurity> servletApi() throws Exception {
		return getOrApply(new ServletApiConfigurer<>());
	}

	/**
	 * Adds CSRF support. This is activated by default when using
	 * WebSecurityConfigurerAdapter's default constructor. 
	 * 
	 *
	 * @return the ServletApiConfigurer for further customizations
	 * @throws Exception
	 */
	public CsrfConfigurer<HttpSecurity> csrf() throws Exception {
		ApplicationContext context = getContext();
		return getOrApply(new CsrfConfigurer<>(context));
	}

	/**
	 * Provides logout support. This is automatically applied when using
	 * WebSecurityConfigurerAdapter. The default is that accessing the URL
	 * "/logout" will log the user out by invalidating the HTTP Session, cleaning up any
	 * #rememberMe() authentication that was configured, clearing the
	 * SecurityContextHolder, and then redirect to "/login?success".
	 *	
	 *
	 * @return the LogoutConfigurer for further customizations
	 * @throws Exception
	 */
	public LogoutConfigurer<HttpSecurity> logout() throws Exception {
		return getOrApply(new LogoutConfigurer<>());
	}

	/**
	 * Allows configuring how an anonymous user is represented. This is automatically
	 * applied when used in conjunction with WebSecurityConfigurerAdapter. By
	 * default anonymous users will be represented with an
	 * org.springframework.security.authentication.AnonymousAuthenticationToken
	 * and contain the role "ROLE_ANONYMOUS".
	 *
	 * @return the AnonymousConfigurer for further customizations
	 * @throws Exception
	 */
	public AnonymousConfigurer<HttpSecurity> anonymous() throws Exception {
		return getOrApply(new AnonymousConfigurer<>());
	}

	/**
	 * Specifies to support form based authentication. If
	 * FormLoginConfigurer#loginPage(String) is not specified a default login page
	 * will be generated.
	 *
	 *
	 * @see FormLoginConfigurer#loginPage(String)
	 *
	 * @return the  FormLoginConfigurer for further customizations
	 * @throws Exception
	 */
	public FormLoginConfigurer<HttpSecurity> formLogin() throws Exception {
		return getOrApply(new FormLoginConfigurer<>());
	}

	/**
	 * Configures authentication support using an OAuth 2.0 and/or OpenID Connect 1.0 Provider.
	 *
	 * @return the OAuth2LoginConfigurer for further customizations
	 * @throws Exception
	 */
	public OAuth2LoginConfigurer<HttpSecurity> oauth2Login() throws Exception {
		return getOrApply(new OAuth2LoginConfigurer<>());
	}

	/**
	 * Configures OAuth 2.0 Client support.
	 *
	 * @since 5.1
	 * @return the OAuth2ClientConfigurer for further customizations
	 * @throws Exception
	 */
	public OAuth2ClientConfigurer<HttpSecurity> oauth2Client() throws Exception {
		OAuth2ClientConfigurer<HttpSecurity> configurer = getOrApply(new OAuth2ClientConfigurer<>());
		this.postProcess(configurer);
		return configurer;
	}

	/**
	 * Configures OAuth 2.0 Resource Server support.
	 *
	 * @since 5.1
	 * @return the OAuth2ResourceServerConfigurer for further customizations
	 * @throws Exception
	 */
	public OAuth2ResourceServerConfigurer<HttpSecurity> oauth2ResourceServer() throws Exception {
		OAuth2ResourceServerConfigurer<HttpSecurity> configurer = 
			getOrApply(new OAuth2ResourceServerConfigurer<>(getContext()));
		this.postProcess(configurer);
		return configurer;
	}

	/**
	 * Configures channel security. In order for this configuration to be useful at least
	 * one mapping to a required channel must be provided.
	 *
	 *
	 * @return the ChannelSecurityConfigurer for further customizations
	 * @throws Exception
	 */
	public ChannelSecurityConfigurer<HttpSecurity>.ChannelRequestMatcherRegistry requiresChannel()
			throws Exception {
		ApplicationContext context = getContext();
		return getOrApply(new ChannelSecurityConfigurer<>(context))
				.getRegistry();
	}

	/**
	 * Configures HTTP Basic authentication.
	 *
	 *
	 * @return the HttpBasicConfigurer for further customizations
	 * @throws Exception
	 */
	public HttpBasicConfigurer<HttpSecurity> httpBasic() throws Exception {
		return getOrApply(new HttpBasicConfigurer<>());
	}

	public <C> void setSharedObject(Class<C> sharedType, C object) {
		super.setSharedObject(sharedType, object);
	}

	@Override
	protected void beforeConfigure() throws Exception {
		setSharedObject(AuthenticationManager.class, getAuthenticationRegistry().build());
	}

	@Override
	protected DefaultSecurityFilterChain performBuild() throws Exception {
		Collections.sort(filters, comparator);
		return new DefaultSecurityFilterChain(requestMatcher, filters);
	}

	/*
	 *
	 * @see
	 * org.springframework.security.config.annotation.web.HttpSecurityBuilder#authenticationProvider
	 * (org.springframework.security.authentication.AuthenticationProvider)
	 */
	public HttpSecurity authenticationProvider(
			AuthenticationProvider authenticationProvider) {
		getAuthenticationRegistry().authenticationProvider(authenticationProvider);
		return this;
	}

	/*
	 *
	 * @see
	 * org.springframework.security.config.annotation.web.HttpSecurityBuilder#userDetailsService
	 * (org.springframework.security.core.userdetails.UserDetailsService)
	 */
	public HttpSecurity userDetailsService(UserDetailsService userDetailsService)
			throws Exception {
		getAuthenticationRegistry().userDetailsService(userDetailsService);
		return this;
	}

	private AuthenticationManagerBuilder getAuthenticationRegistry() {
		return getSharedObject(AuthenticationManagerBuilder.class);
	}

	/*
	 *
	 * @see
	 * org.springframework.security.config.annotation.web.HttpSecurityBuilder#addFilterAfter(javax
	 * .servlet.Filter, java.lang.Class)
	 */
	public HttpSecurity addFilterAfter(Filter filter, Class<? extends Filter> afterFilter) {
		comparator.registerAfter(filter.getClass(), afterFilter);
		return addFilter(filter);
	}

	/*
	 *
	 * @see
	 * org.springframework.security.config.annotation.web.HttpSecurityBuilder#addFilterBefore(
	 * javax.servlet.Filter, java.lang.Class)
	 */
	public HttpSecurity addFilterBefore(Filter filter,
			Class<? extends Filter> beforeFilter) {
		comparator.registerBefore(filter.getClass(), beforeFilter);
		return addFilter(filter);
	}

	/*
	 *
	 * @see
	 * org.springframework.security.config.annotation.web.HttpSecurityBuilder#addFilter(javax.
	 * servlet.Filter)
	 */
	public HttpSecurity addFilter(Filter filter) {
		Class<? extends Filter> filterClass = filter.getClass();
		if (!comparator.isRegistered(filterClass)) {
			throw new IllegalArgumentException(
					"The Filter class "
							+ filterClass.getName()
							+ " does not have a registered order and cannot be added "
							+ " without a specified order. "
                            + " Consider using addFilterBefore or addFilterAfter instead.");
		}
		this.filters.add(filter);
		return this;
	}

	/**
	 * Adds the Filter at the location of the specified Filter class. For example, if you
	 * want the filter CustomFilter to be registered in the same position as
	 * UsernamePasswordAuthenticationFilter, you can invoke:
	 *
	 * 
	 * addFilterAt(new CustomFilter(), UsernamePasswordAuthenticationFilter.class)
	 * 
	 *
	 * Registration of multiple Filters in the same location means their ordering is not
	 * deterministic. More concretely, registering multiple Filters in the same location
	 * does not override existing Filters. Instead, do not register Filters you do not
	 * want to use.
	 *
	 * @param filter the Filter to register
	 * @param atFilter the location of another Filter that is already registered
	 * (i.e. known) with Spring Security.
	 * @return the HttpSecurity for further customizations
	 */
	public HttpSecurity addFilterAt(Filter filter, Class<? extends Filter> atFilter) {
		this.comparator.registerAt(filter.getClass(), atFilter);
		return addFilter(filter);
	}

	/**
	 * Allows specifying which HttpServletRequest instances this
	 * HttpSecurity will be invoked on. This method allows for easily invoking the
	 * HttpSecurity for multiple different RequestMatcher instances. If
	 * only a single RequestMatcher is necessary consider using #mvcMatcher(String),
	 * #antMatcher(String), #regexMatcher(String), or
	 * #requestMatcher(RequestMatcher).
	 *
	 *
	 * Invoking #requestMatchers() will not override previous invocations of #mvcMatcher(String),
	 * #requestMatchers(), #antMatcher(String),
	 * #regexMatcher(String), and requestMatcher(RequestMatcher).
	 * 
	 *
	 *
	 * @return the RequestMatcherConfigurer for further customizations
	 */
	public RequestMatcherConfigurer requestMatchers() {
		return requestMatcherConfigurer;
	}

	/**
	 * Allows configuring the HttpSecurity to only be invoked when matching the
	 * provided RequestMatcher. If more advanced configuration is necessary,
	 * consider using #requestMatchers().
	 *
	 * 
	 * Invoking #requestMatcher(RequestMatcher) will override previous invocations
	 * of #requestMatchers(), #mvcMatcher(String), #antMatcher(String),
	 * #regexMatcher(String), and #requestMatcher(RequestMatcher).
	 * 
	 *
	 * @param requestMatcher the RequestMatcher to use (i.e. new
	 * AntPathRequestMatcher("/admin/**","GET") )
	 * @return the HttpSecurity or further customizations
	 * @see #requestMatchers()
	 * @see #antMatcher(String)
	 * @see #regexMatcher(String)
	 */
	public HttpSecurity requestMatcher(RequestMatcher requestMatcher) {
		this.requestMatcher = requestMatcher;
		return this;
	}

	/**
	 * Allows configuring the HttpSecurity to only be invoked when matching the
	 * provided ant pattern. If more advanced configuration is necessary, consider using
	 * #requestMatchers() or #requestMatcher(RequestMatcher).
	 *
	 * 
	 * Invoking #antMatcher(String) will override previous invocations of #mvcMatcher(String),
	 * #requestMatchers(), #antMatcher(String),
	 * #regexMatcher(String), and #requestMatcher(RequestMatcher).
	 * 
	 *
	 * @param antPattern the Ant Pattern to match on (i.e. "/admin/**")
	 * @return the HttpSecurity for further customizations
	 * @see AntPathRequestMatcher
	 */
	public HttpSecurity antMatcher(String antPattern) {
		return requestMatcher(new AntPathRequestMatcher(antPattern));
	}

	/**
	 * Allows configuring the HttpSecurity to only be invoked when matching the
	 * provided Spring MVC pattern. If more advanced configuration is necessary, consider using
	 * #requestMatchers() or #requestMatcher(RequestMatcher).
	 *
	 * 
	 * Invoking #mvcMatcher(String) will override previous invocations of #mvcMatcher(String),
	 * #requestMatchers(), #antMatcher(String),
	 * #regexMatcher(String), and #requestMatcher(RequestMatcher).
	 * 
	 *
	 * @param mvcPattern the Spring MVC Pattern to match on (i.e. "/admin/**")
	 * @return the HttpSecurity for further customizations
	 * @see MvcRequestMatcher
	 */
	public HttpSecurity mvcMatcher(String mvcPattern) {
		HandlerMappingIntrospector introspector = new HandlerMappingIntrospector(getContext());
		return requestMatcher(new MvcRequestMatcher(introspector, mvcPattern));
	}

	/**
	 * Allows configuring the HttpSecurity to only be invoked when matching the
	 * provided regex pattern. If more advanced configuration is necessary, consider using
	 * #requestMatchers() or #requestMatcher(RequestMatcher).
	 *
	 *
	 * Invoking #regexMatcher(String) will override previous invocations of #mvcMatcher(String),
	 * #requestMatchers(), #antMatcher(String),
	 * #regexMatcher(String), and #requestMatcher(RequestMatcher).
	 * 
	 *
	 * @param pattern the Regular Expression to match on (i.e. "/admin/.+")
	 * @return the HttpSecurity for further customizations
	 * @see RegexRequestMatcher
	 */
	public HttpSecurity regexMatcher(String pattern) {
		return requestMatcher(new RegexRequestMatcher(pattern, null));
	}

	/**
	 * An extension to RequestMatcherConfigurer that allows optionally configuring
	 * the servlet path.
	 *
	 * @author Rob Winch
	 */
	public final class MvcMatchersRequestMatcherConfigurer extends RequestMatcherConfigurer {

		/**
		 * Creates a new instance
		 * @param context the ApplicationContext to use
		 * @param matchers the MvcRequestMatcher instances to set the servlet path
		 * on if #servletPath(String) is set.
		 */
		private MvcMatchersRequestMatcherConfigurer(ApplicationContext context,
				List<MvcRequestMatcher> matchers) {
			super(context);
			this.matchers = new ArrayList<>(matchers);
		}

		public RequestMatcherConfigurer servletPath(String servletPath) {
			for (RequestMatcher matcher : this.matchers) {
				((MvcRequestMatcher) matcher).setServletPath(servletPath);
			}
			return this;
		}

	}

	/**
	 * Allows mapping HTTP requests that this HttpSecurity will be used for
	 *
	 * @author Rob Winch
	 * @since 3.2
	 */
	public class RequestMatcherConfigurer
			extends AbstractRequestMatcherRegistry<RequestMatcherConfigurer> {

		protected List<RequestMatcher> matchers = new ArrayList<>();

		/**
		 * @param context
		 */
		private RequestMatcherConfigurer(ApplicationContext context) {
			setApplicationContext(context);
		}

		@Override
		public MvcMatchersRequestMatcherConfigurer mvcMatchers(HttpMethod method,
				String... mvcPatterns) {
			List<MvcRequestMatcher> mvcMatchers = createMvcMatchers(method, mvcPatterns);
			setMatchers(mvcMatchers);
			return new MvcMatchersRequestMatcherConfigurer(getContext(), mvcMatchers);
		}

		@Override
		public MvcMatchersRequestMatcherConfigurer mvcMatchers(String... patterns) {
			return mvcMatchers(null, patterns);
		}

		@Override
		protected RequestMatcherConfigurer chainRequestMatchers(
				List<RequestMatcher> requestMatchers) {
			setMatchers(requestMatchers);
			return this;
		}

		private void setMatchers(List<? extends RequestMatcher> requestMatchers) {
			this.matchers.addAll(requestMatchers);
			requestMatcher(new OrRequestMatcher(this.matchers));
		}

		/**
		 * Return the HttpSecurity for further customizations
		 *
		 * @return the HttpSecurity for further customizations
		 */
		public HttpSecurity and() {
			return HttpSecurity.this;
		}

	}

	/**
	 * If the SecurityConfigurer has already been specified get the original,
	 * otherwise apply the new SecurityConfigurerAdapter.
	 *
	 * @param configurer the SecurityConfigurer to apply if one is not found for
	 * this SecurityConfigurer class.
	 * @return the current SecurityConfigurer for the configurer passed in
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	private <C extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>> 
			C getOrApply(C configurer) throws Exception {
		C existingConfig = (C) getConfigurer(configurer.getClass());
		if (existingConfig != null) {
			return existingConfig;
		}
		return apply(configurer);
	}
}

参考文章

Spring Security : 配置 HttpSecurity 的 SecurityConfigurer
Spring Security : 安全构建器HttpSecurity和WebSecurity的区别
Spring Security : Web安全构建器 WebSecurity

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值