官方在线文档:
https://docs.spring.io/spring-security/reference/index.html
Spring Security 自动配置:
在引入的jar包spring-boot-autoconfigure-3.0.5.jar中,
目录:\META-INF\spring\org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中,可以找到如下配置:
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration
SecurityAutoConfiguration中:
@AutoConfiguration @ConditionalOnClass({DefaultAuthenticationEventPublisher.class}) @EnableConfigurationProperties({SecurityProperties.class}) @Import({SpringBootWebSecurityConfiguration.class, SecurityDataConfiguration.class}) public class SecurityAutoConfiguration { public SecurityAutoConfiguration() { } @Bean @ConditionalOnMissingBean({AuthenticationEventPublisher.class}) public DefaultAuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher publisher) { return new DefaultAuthenticationEventPublisher(publisher); } }
其中导入了SpringBootWebSecurityConfiguration:
@Configuration(proxyBeanMethods = false) @ConditionalOnWebApplication(type = Type.SERVLET) class SpringBootWebSecurityConfiguration { /** * The default configuration for web security. It relies on Spring Security's * content-negotiation strategy to determine what sort of authentication to use. If * the user specifies their own {@link SecurityFilterChain} bean, this will back-off * completely and the users should specify all the bits that they want to configure as * part of the custom security configuration. */ @Configuration(proxyBeanMethods = false) @ConditionalOnDefaultWebSecurity static class SecurityFilterChainConfiguration { @Bean @Order(SecurityProperties.BASIC_AUTH_ORDER) SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests().anyRequest().authenticated(); http.formLogin(); http.httpBasic(); return http.build(); } } /** * Adds the {@link EnableWebSecurity @EnableWebSecurity} annotation if Spring Security * is on the classpath. This will make sure that the annotation is present with * default security auto-configuration and also if the user adds custom security and * forgets to add the annotation. If {@link EnableWebSecurity @EnableWebSecurity} has * already been added or if a bean with name * {@value BeanIds#SPRING_SECURITY_FILTER_CHAIN} has been configured by the user, this * will back-off. */ @Configuration(proxyBeanMethods = false) @ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN) @ConditionalOnClass(EnableWebSecurity.class) @EnableWebSecurity static class WebSecurityEnablerConfiguration { } }
找到@EnableWebSecurity源码:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class, HttpSecurityConfiguration.class }) @EnableGlobalAuthentication public @interface EnableWebSecurity { /** * Controls debugging support for Spring Security. Default is false. * @return if true, enables debug support with Spring Security */ boolean debug() default false; }
其中又导入了HttpSecurityConfiguration,看其源码:
@Bean(HTTPSECURITY_BEAN_NAME) @Scope("prototype") HttpSecurity httpSecurity() throws Exception { LazyPasswordEncoder passwordEncoder = new LazyPasswordEncoder(this.context); AuthenticationManagerBuilder authenticationBuilder = new DefaultPasswordEncoderAuthenticationManagerBuilder( this.objectPostProcessor, passwordEncoder); authenticationBuilder.parentAuthenticationManager(authenticationManager()); authenticationBuilder.authenticationEventPublisher(getAuthenticationEventPublisher()); HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, createSharedObjects()); WebAsyncManagerIntegrationFilter webAsyncManagerIntegrationFilter = new WebAsyncManagerIntegrationFilter(); webAsyncManagerIntegrationFilter.setSecurityContextHolderStrategy(this.securityContextHolderStrategy); // @formatter:off http .csrf(withDefaults()) .addFilter(webAsyncManagerIntegrationFilter) .exceptionHandling(withDefaults()) .headers(withDefaults()) .sessionManagement(withDefaults()) .securityContext(withDefaults()) .requestCache(withDefaults()) .anonymous(withDefaults()) .servletApi(withDefaults()) .apply(new DefaultLoginPageConfigurer<>()); http.logout(withDefaults()); // @formatter:on applyDefaultConfigurers(http); return http; }
注意其中这句:
HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, createSharedObjects());
找到HttpSecurity源码:
public final class HttpSecurity extends AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity> implements SecurityBuilder<DefaultSecurityFilterChain>, HttpSecurityBuilder<HttpSecurity> { private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector"; private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector"; private static final boolean mvcPresent; private final RequestMatcherConfigurer requestMatcherConfigurer; private List<OrderedFilter> filters = new ArrayList<>(); private RequestMatcher requestMatcher = AnyRequestMatcher.INSTANCE; private FilterOrderRegistration filterOrders = new FilterOrderRegistration(); private AuthenticationManager authenticationManager; static { mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR, HttpSecurity.class.getClassLoader()); } /** * Creates a new instance * @param objectPostProcessor the {@link ObjectPostProcessor} that should be used * @param authenticationBuilder the {@link AuthenticationManagerBuilder} to use for * additional updates * @param sharedObjects the shared Objects to initialize the {@link HttpSecurity} with * @see WebSecurityConfiguration */ @SuppressWarnings("unchecked") public HttpSecurity(ObjectPostProcessor<Object> objectPostProcessor, AuthenticationManagerBuilder authenticationBuilder, Map<Class<?>, Object> sharedObjects) { super(objectPostProcessor); Assert.notNull(authenticationBuilder, "authenticationBuilder cannot be null"); setSharedObject(AuthenticationManagerBuilder.class, authenticationBuilder); for (Map.Entry<Class<?>, Object> entry : sharedObjects.entrySet()) { setSharedObject((Class<Object>) entry.getKey(), entry.getValue()); } ApplicationContext context = (ApplicationContext) sharedObjects.get(ApplicationContext.class); this.requestMatcherConfigurer = new RequestMatcherConfigurer(context); } ......
注意其中这句:
private FilterOrderRegistration filterOrders = new FilterOrderRegistration();
找到其源码:
final class FilterOrderRegistration { private static final int INITIAL_ORDER = 100; private static final int ORDER_STEP = 100; private final Map<String, Integer> filterToOrder = new HashMap<>(); FilterOrderRegistration() { Step order = new Step(INITIAL_ORDER, ORDER_STEP); put(DisableEncodeUrlFilter.class, order.next()); put(ForceEagerSessionCreationFilter.class, order.next()); put(ChannelProcessingFilter.class, order.next()); order.next(); // gh-8105 put(WebAsyncManagerIntegrationFilter.class, order.next()); put(SecurityContextHolderFilter.class, order.next()); put(SecurityContextPersistenceFilter.class, order.next()); put(HeaderWriterFilter.class, order.next()); put(CorsFilter.class, order.next()); put(CsrfFilter.class, order.next()); put(LogoutFilter.class, order.next()); this.filterToOrder.put( "org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter", order.next()); this.filterToOrder.put( "org.springframework.security.saml2.provider.service.web.Saml2WebSsoAuthenticationRequestFilter", order.next()); put(X509AuthenticationFilter.class, order.next()); put(AbstractPreAuthenticatedProcessingFilter.class, order.next()); this.filterToOrder.put("org.springframework.security.cas.web.CasAuthenticationFilter", order.next()); this.filterToOrder.put("org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter", order.next()); this.filterToOrder.put( "org.springframework.security.saml2.provider.service.web.authentication.Saml2WebSsoAuthenticationFilter", order.next()); put(UsernamePasswordAuthenticationFilter.class, order.next()); order.next(); // gh-8105 put(DefaultLoginPageGeneratingFilter.class, order.next()); put(DefaultLogoutPageGeneratingFilter.class, order.next()); put(ConcurrentSessionFilter.class, order.next()); put(DigestAuthenticationFilter.class, order.next()); this.filterToOrder.put( "org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter", order.next()); put(BasicAuthenticationFilter.class, order.next()); put(RequestCacheAwareFilter.class, order.next()); put(SecurityContextHolderAwareRequestFilter.class, order.next()); put(JaasApiIntegrationFilter.class, order.next()); put(RememberMeAuthenticationFilter.class, order.next()); put(AnonymousAuthenticationFilter.class, order.next()); this.filterToOrder.put("org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter", order.next()); put(SessionManagementFilter.class, order.next()); put(ExceptionTranslationFilter.class, order.next()); put(FilterSecurityInterceptor.class, order.next()); put(AuthorizationFilter.class, order.next()); put(SwitchUserFilter.class, order.next()); } ......
注意这个HashMap:
private final Map<String, Integer> filterToOrder = new HashMap<>();
构造函数在向里面加默认的过滤器。
关于默认不保存登录凭证的问题:
https://github.com/spring-projects/spring-security/issues/11110
参考:
- Spring Security 6.0 中的新增功能
- Spring Security 6 配置方法,废弃 WebSecurityConfigurerAdapter
- WebSecurityConfigurerAdapter已弃用
- Spring Security 6 注解使用
- Spring Security 6.0(spring boot 3.0) 下认证配置流程
- AccessDecisionVoter Deprecated with Spring Security 6.x
- SpringBoot3.0 + SpringSecurity6.0+JWT
- 聊聊 Spring Security 的新接口 AuthorizationManager
- Spring Boot Security Configuration, practically explained — Part6: A deep intro to filter/token-based security
- 在Spring Security 5.7.6中有效的配置规则在6.0.1中无效
- Spring Security 6.0系列【1】基础篇之概述及入门案例
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END