Spring Security 6.x 系列(10)—— SecurityConfigurer 配置器及其分支实现源码分析(二)
一、前言
在本系列文章:
Spring Security 6.x 系列(4)—— 基于过滤器链的源码分析(一)
中着重分析了Spring Security在Spring Boot自动配置、 DefaultSecurityFilterChain和FilterChainProxy 的构造过程。
Spring Security 6.x 系列(7)—— SecurityBuilder 继承链源码分析
中详细分析了Spring Security中WebSecurity、HttpSecurity、AuthenticationManagerBuilder 三个构造器的公共继承链。
Spring Security 6.x 系列(8)—— SecurityConfigurer 配置器及其分支实现源码分析(一)
中分析SecurityConfigurer配置器及其主要分支实现。
Spring Security 6.x 系列(9)—— 基于过滤器链的源码分析(二)
着重分析了@EnableGlobalAuthentication注解的作用、对AuthenticationConfiguration构造AuthenticationManager过程和上文中未介绍的GlobalAuthenticationConfigurerAdapter 配置器的五个分支实现进行了详细的说明。
今天我们就从未被介绍的SecurityConfigurerAdapter配置器的具体分支实现进行展开。
二、SecurityConfigurerAdapter
SecurityConfigurerAdapter在上文中有过详解介绍,它是SecurityConfigurer的基类,它允许子类仅实现它们感兴趣的方法。它还提供了使用 SecurityConfigurer以及完成后获取正在配置的SecurityBuilder(构造器)的访问权限的机制。
SecurityConfigurerAdapter 的实现主要有三大类:
UserDetailsAwareConfigurerAbstractHttpConfigurerLdapAuthenticationProviderConfigurer
考虑到 LDAP 现在使用很少,所以重点介绍前两个。
三、UserDetailsAwareConfigurer
从这个类名就能大概知道是和用户详细信息配置有关。
再通过继承关系图,看看UserDetailsAwareConfigurer的顶层架构设计:

UserDetailsAwareConfigurer是一个抽象类,源码比较简单:
/**
* Base class that allows access to the {@link UserDetailsService} for using as a default
* value with {@link AuthenticationManagerBuilder}.
*
* @param <B> the type of the {@link ProviderManagerBuilder}
* @param <U> the type of {@link UserDetailsService}
* @author Rob Winch
*/
public abstract class UserDetailsAwareConfigurer<B extends ProviderManagerBuilder<B>, U extends UserDetailsService>
extends SecurityConfigurerAdapter<AuthenticationManager, B> {
/**
* Gets the {@link UserDetailsService} or null if it is not available
* @return the {@link UserDetailsService} or null if it is not available
*/
public abstract U getUserDetailsService();
}
通过源码我们可知:
-
泛型
U继承了UserDetailsService接口,也就意味着
getUserDetailsService()方法返回的对象肯定是UserDetailsService接口的实现。 -
泛型
B继承了ProviderManagerBuilder接口,ProviderManagerBuilder构造器的作用是用来构建AuthenticationManager对象,可就意味UserDetailsAwareConfigurer(配置器)用来配置ProviderManagerBuilder构造器。
3.1 AbstractDaoAuthenticationConfigurer
AbstractDaoAuthenticationConfigurer也是一个抽象类,是模版模式:
/**
* Allows configuring a {@link DaoAuthenticationProvider}
*
* @param <B> the type of the {@link SecurityBuilder}
* @param <C> the type of {@link AbstractDaoAuthenticationConfigurer} this is
* @param <U> The type of {@link UserDetailsService} that is being used
* @author Rob Winch
* @since 3.2
*/
public abstract class AbstractDaoAuthenticationConfigurer<B extends ProviderManagerBuilder<B>, C extends AbstractDaoAuthenticationConfigurer<B, C, U>, U extends UserDetailsService>
extends UserDetailsAwareConfigurer<B, U> {
// 声明了一个 provider
private DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
// 声明了一个 userDetailsService 的泛型属性
private final U userDetailsService;
/**
* 创建一个实例
* @param userDetailsService,userDetailsService的类型可以是UserDetailsService或者UserDetailsPasswordService
*/
AbstractDaoAuthenticationConfigurer(U userDetailsService) {
this.userDetailsService = userDetailsService;
this.provider.setUserDetailsService(userDetailsService);
if (userDetailsService instanceof UserDetailsPasswordService) {
this.provider.setUserDetailsPasswordService((UserDetailsPasswordService) userDetailsService);
}
}
/**
* Adds an {@link ObjectPostProcessor} for this class.
* @param objectPostProcessor
* @return the {@link AbstractDaoAuthenticationConfigurer} for further customizations
*/
@SuppressWarnings("unchecked")
public C withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
addObjectPostProcessor(objectPostProcessor);
return (C) this;
}
/**
* Allows specifying the {@link PasswordEncoder} to use with the
* {@link DaoAuthenticationProvider}. The default is to use plain text.
* @param passwordEncoder The {@link PasswordEncoder} to use.
* @return the {@link AbstractDaoAuthenticationConfigurer} for further customizations
*/
@SuppressWarnings("unchecked")
public C passwordEncoder(PasswordEncoder passwordEncoder) {
this.provider.setPasswordEncoder(passwordEncoder);
return (C) this;
}
public C userDetailsPasswordManager(UserDetailsPasswordService passwordManager) {
this.provider.setUserDetailsPasswordService(passwordManager);
return (C) this;
}
@Override
public void configure(B builder) throws Exception {
this.provider = postProcess(this.provider);
// 向builder添加provider(配置构造器阶段)
builder.authenticationProvider(this.provider);
}
/**
* Gets the {@link UserDetailsService} that is used with the
* {@link DaoAuthenticationProvider}
* @return the {@link UserDetailsService} that is used with the
* {@link DaoAuthenticationProvider}
*/
@Override
public U getUserDetailsService() {
return this.userDetailsService;
}
}
通过源码我们可知:
AbstractDaoAuthenticationConfigurer初始时创建了一个DaoAuthenticationProvider类型的AuthenticationProvider实例。- 为使用者提供设置
DaoAuthenticationProvider属性UserDetailsService的功能并指定类型为:UserDetailsService/U serDetailsPasswordService。 - 为使用者提供设置
DaoAuthenticationProvider属性PasswordEncoder功能; - 为使用者提供设置对象后置处处理器的功能。
AbstractDaoAuthenticationConfigurer配置构造器对应的初始化阶段方法为空。AbstractDaoAuthenticationConfigurer配置构造器对应的配置阶段方法:- 对
DaoAuthenticationProvider执行后置处理 - 将
DaoAuthenticationProvider添加到构造器中
- 对
3.2 DaoAuthenticationConfigurer
DaoAuthenticationConfigurer继承自 AbstractDaoAuthenticationConfigurer,在构造方法中调用AbstractDaoAuthenticationConfigurer的构造方法。
/**
* Allows configuring a {@link DaoAuthenticationProvider}
*
* @param <B> The type of {@link ProviderManagerBuilder} this is
* @param <U> The type of {@link UserDetailsService} that is being used
* @author Rob Winch
* @since 3.2
*/
public class DaoAuthenticationConfigurer<B extends ProviderManagerBuilder<B>, U extends UserDetailsService>
extends AbstractDaoAuthenticationConfigurer<B, DaoAuthenticationConfigurer<B, U>, U> {
/**
* Creates a new instance
* @param userDetailsService
*/
public DaoAuthenticationConfigurer(U userDetailsService) {
super(userDetailsService);
}
}
3.3 UserDetailsServiceConfigurer
UserDetailsServiceConfigurer继承了AbstractDaoAuthenticationConfigurer,并重写了AbstractDaoAuthenticationConfigurer中的configure方法,在configure方法执行之前加入了initUserDetailsService方法,以方便开发时按照自己的方式去初始化 UserDetailsService。这里的initUserDetailsService方法是空的,会交于子类进行具体实现,也是模版模式。
/**
* Allows configuring a {@link UserDetailsService} within a
* {@link AuthenticationManagerBuilder}.
*
* @param <B> the type of the {@link ProviderManagerBuilder}
* @param <C> the {@link UserDetailsServiceConfigurer} (or this)
* @param <U> the type of UserDetailsService being used to allow for returning the
* concrete UserDetailsService.
* @author Rob Winch
* @since 3.2
*/
public class UserDetailsServiceConfigurer<B extends ProviderManagerBuilder<B>, C extends UserDetailsServiceConfigurer<B, C, U>, U extends UserDetailsService>
extends AbstractDaoAuthenticationConfigurer<B, C, U> {
/**
* Creates a new instance
* @param userDetailsService the {@link UserDetailsService} that should be used
*/
public UserDetailsServiceConfigurer(U userDetailsService) {
super(userDetailsService);
}
@Override
public void configure(B builder) throws Exception {
initUserDetailsService();
super.configure(builder);
}
/**
* Allows subclasses to initialize the {@link UserDetailsService}. For example, it
* might add users, initialize schema, etc.
*/
protected void initUserDetailsService() throws Exception {
}
}
3.4 UserDetailsManagerConfigurer
UserDetailsManagerConfigurer继承了UserDetailsServiceConfigurer,并实现了 UserDetailsServiceConfigurer中定义的initUserDetailsService空方法,具体的实现逻辑就是将UserDetailsBuilder所构建出来的 UserDetails以及提前准备好的UserDetails中的用户存储到UserDetailsService中。
在实例构造上进一步限制了父类中的U userDetailsService的类型为UserDetailsManager。

该类同时添加 withUser方法用来添加用户,同时还增加了一个UserDetailsBuilder用来构建用户,这些逻辑都比较简单,大家可以自行查看。
/**
* Base class for populating an
* {@link org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder}
* with a {@link UserDetailsManager}.
*
* @param <B> the type of the {@link SecurityBuilder} that is being configured
* @param <C> the type of {@link UserDetailsManagerConfigurer}
* @author Rob Winch
* @since 3.2
*/
public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C extends UserDetailsManagerConfigurer<B, C>>
extends UserDetailsServiceConfigurer<B, C, UserDetailsManager> {
private final List<UserDetailsBuilder> userBuilders = new ArrayList<>();
private final List<UserDetails> users = new ArrayList<>();
protected UserDetailsManagerConfigurer(UserDetailsManager userDetailsManager) {
super(userDetailsManager);
}
/**
* Populates the users that have been added.
* @throws Exception
*/
@Override
protected void initUserDetailsService() throws Exception {
for (UserDetailsBuilder userBuilder : this.userBuilders) {
getUserDetailsService().createUser(userBuilder.build());
}
for (UserDetails userDetails : this.users) {
getUserDetailsService().createUser(userDetails);
}
}
/**
* Allows adding a user to the {@link UserDetailsManager} that is being created. This
* method can be invoked multiple times to add multiple users.
* @param userDetails the user to add. Cannot be null.
* @return the {@link UserDetailsBuilder} for further customizations
*/
@SuppressWarnings("unchecked")
public final C withUser(UserDetails userDetails) {
this.users.add(userDetails);
return (C) this;
}
/**
* Allows adding a user to the {@link UserDetailsManager} that is being created. This
* method can be invoked multiple times to add multiple users.
* @param userBuilder the user to add. Cannot be null.
* @return the {@link UserDetailsBuilder} for further customizations
*/
@SuppressWarnings("unchecked")
public final C withUser(User.UserBuilder userBuilder) {
this.users.add(userBuilder.build());
return (C) this;
}
/**
* Allows adding a user to the {@link UserDetailsManager} that is being created. This
* method can be invoked multiple times to add multiple users.
* @param username the username for the user being added. Cannot be null.
* @return the {@link UserDetailsBuilder} for further customizations
*/
@SuppressWarnings("unchecked")
public final UserDetailsBuilder withUser(String username) {
UserDetailsBuilder userBuilder = new UserDetailsBuilder((C) this);
userBuilder.username(username);
this.userBuilders.add(userBuilder);
return userBuilder;
}
/**
* Builds the user to be added. At minimum the username, password, and authorities
* should provided. The remaining attributes have reasonable defaults.
*/
public final class UserDetailsBuilder {
private UserBuilder user;
private final C builder;
/**
* Creates a new instance
* @param builder the builder to return
*/
private UserDetailsBuilder(C builder) {
this.builder = builder;
}
/**
* Returns the {@link UserDetailsManagerConfigurer} for method chaining (i.e. to
* add another user)
* @return the {@link UserDetailsManagerConfigurer} for method chaining
*/
public C and() {
return this.builder;
}
/**
* Populates the username. This attribute is required.
* @param username the username. Cannot be null.
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate
* additional attributes for this user)
*/
private UserDetailsBuilder username(String username) {
this.user = User.withUsername(username);
return this;
}
/**
* Populates the password. This attribute is required.
* @param password the password. Cannot be null.
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate
* additional attributes for this user)
*/
public UserDetailsBuilder password(String password) {
this.user.password(password);
return this;
}
/**
* Populates the roles. This method is a shortcut for calling
* {@link #authorities(String...)}, but automatically prefixes each entry with
* "ROLE_". This means the following:
*
* <code>
* builder.roles("USER","ADMIN");
* </code>
*
* is equivalent to
*
* <code>
* builder.authorities("ROLE_USER","ROLE_ADMIN");
* </code>
*
* <p>
* This attribute is required, but can also be populated with
* {@link #authorities(String...)}.
* </p>
* @param roles the roles for this user (i.e. USER, ADMIN, etc). Cannot be null,
* contain null values or start with "ROLE_"
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate
* additional attributes for this user)
*/
public UserDetailsBuilder roles(String... roles) {
this.user.roles(roles);
return this;
}
/**
* Populates the authorities. This attribute is required.
* @param authorities the authorities for this user. Cannot be null, or contain
* null values
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate
* additional attributes for this user)
* @see #roles(String...)
*/
public UserDetailsBuilder authorities(GrantedAuthority... authorities) {
this.user.authorities(authorities);
return this;
}
/**
* Populates the authorities. This attribute is required.
* @param authorities the authorities for this user. Cannot be null, or contain
* null values
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate
* additional attributes for this user)
* @see #roles(String...)
*/
public UserDetailsBuilder authorities(List<? extends GrantedAuthority> authorities) {
this.user.authorities(authorities);
return this;
}
/**
* Populates the authorities. This attribute is required.
* @param authorities the authorities for this user (i.e. ROLE_USER, ROLE_ADMIN,
* etc). Cannot be null, or contain null values
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate
* additional attributes for this user)
* @see #roles(String...)
*/
public UserDetailsBuilder authorities(String... authorities) {
this.user.authorities(authorities);
return this;
}
/**
* Defines if the account is expired or not. Default is false.
* @param accountExpired true if the account is expired, false otherwise
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate
* additional attributes for this user)
*/
public UserDetailsBuilder accountExpired(boolean accountExpired) {
this.user.accountExpired(accountExpired);
return this;
}
/**
* Defines if the account is locked or not. Default is false.
* @param accountLocked true if the account is locked, false otherwise
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate
* additional attributes for this user)
*/
public UserDetailsBuilder accountLocked(boolean accountLocked) {
this.user.accountLocked(accountLocked);
return this;
}
/**
* Defines if the credentials are expired or not. Default is false.
* @param credentialsExpired true if the credentials are expired, false otherwise
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate
* additional attributes for this user)
*/
public UserDetailsBuilder credentialsExpired(boolean credentialsExpired) {
this.user.credentialsExpired(credentialsExpired);
return this;
}
/**
* Defines if the account is disabled or not. Default is false.
* @param disabled true if the account is disabled, false otherwise
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate
* additional attributes for this user)
*/
public UserDetailsBuilder disabled(boolean disabled) {
this.user.disabled(disabled);
return this;
}
UserDetails build() {
return this.user.build();
}
}
}
3.5 JdbcUserDetailsManagerConfigurer
JdbcUserDetailsManagerConfigurer继承了UserDetailsManagerConfigurer,在父类的基础上补充了 DataSource对象,同时还提供了相应的数据库查询方法。
/**
* Configures an
* {@link org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder}
* to have JDBC authentication. It also allows easily adding users to the database used
* for authentication and setting up the schema.
*
* <p>
* The only required method is the {@link #dataSource(javax.sql.DataSource)} all other
* methods have reasonable defaults.
*
* @param <B> the type of the {@link ProviderManagerBuilder} that is being configured
* @author Rob Winch
* @since 3.2
*/
public class JdbcUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>>
extends UserDetailsManagerConfigurer<B, JdbcUserDetailsManagerConfigurer<B>> {
private DataSource dataSource;
private List<Resource> initScripts = new ArrayList<>();
public JdbcUserDetailsManagerConfigurer(JdbcUserDetailsManager manager) {
super(manager);
}
public JdbcUserDetailsManagerConfigurer() {
this(new JdbcUserDetailsManager());
}
/**
* Populates the {@link DataSource} to be used. This is the only required attribute.
* @param dataSource the {@link DataSource} to be used. Cannot be null.
* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
* customizations
*/
public JdbcUserDetailsManagerConfigurer<B> dataSource(DataSource dataSource) {
this.dataSource = dataSource;
getUserDetailsService().setDataSource(dataSource);
return this;
}
/**
* Sets the query to be used for finding a user by their username. For example:
*
* <code>
* select username,password,enabled from users where username = ?
* </code>
* @param query The query to use for selecting the username, password, and if the user
* is enabled by username. Must contain a single parameter for the username.
* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
* customizations
*/
public JdbcUserDetailsManagerConfigurer<B> usersByUsernameQuery(String query) {
getUserDetailsService().setUsersByUsernameQuery(query);
return this;
}
/**
* Sets the query to be used for finding a user's authorities by their username. For
* example:
*
* <code>
* select username,authority from authorities where username = ?
* </code>
* @param query The query to use for selecting the username, authority by username.
* Must contain a single parameter for the username.
* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
* customizations
*/
public JdbcUserDetailsManagerConfigurer<B> authoritiesByUsernameQuery(String query) {
getUserDetailsService().setAuthoritiesByUsernameQuery(query);
return this;
}
/**
* An SQL statement to query user's group authorities given a username. For example:
*
* <code>
* select
* g.id, g.group_name, ga.authority
* from
* groups g, group_members gm, group_authorities ga
* where
* gm.username = ? and g.id = ga.group_id and g.id = gm.group_id
* </code>
* @param query The query to use for selecting the authorities by group. Must contain
* a single parameter for the username.
* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
* customizations
*/
public JdbcUserDetailsManagerConfigurer<B> groupAuthoritiesByUsername(String query) {
JdbcUserDetailsManager userDetailsService = getUserDetailsService();
userDetailsService.setEnableGroups(true);
userDetailsService.setGroupAuthoritiesByUsernameQuery(query);
return this;
}
/**
* A non-empty string prefix that will be added to role strings loaded from persistent
* storage (default is "").
* @param rolePrefix
* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
* customizations
*/
public JdbcUserDetailsManagerConfigurer<B> rolePrefix(String rolePrefix) {
getUserDetailsService().setRolePrefix(rolePrefix);
return this;
}
/**
* Defines the {@link UserCache} to use
* @param userCache the {@link UserCache} to use
* @return the {@link JdbcUserDetailsManagerConfigurer} for further customizations
*/
public JdbcUserDetailsManagerConfigurer<B> userCache(UserCache userCache) {
getUserDetailsService().setUserCache(userCache);
return this;
}
@Override
protected void initUserDetailsService() throws Exception {
if (!this.initScripts.isEmpty()) {
getDataSourceInit().afterPropertiesSet();
}
super.initUserDetailsService();
}
@Override
public JdbcUserDetailsManager getUserDetailsService() {
return (JdbcUserDetailsManager) super.getUserDetailsService();
}
/**
* Populates the default schema that allows users and authorities to be stored.
* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
* customizations
*/
public JdbcUserDetailsManagerConfigurer<B> withDefaultSchema() {
this.initScripts.add(new ClassPathResource("org/springframework/security/core/userdetails/jdbc/users.ddl"));
return this;
}
protected DatabasePopulator getDatabasePopulator() {
ResourceDatabasePopulator dbp = new ResourceDatabasePopulator();
dbp.setScripts(this.initScripts.toArray(new Resource[0]));
return dbp;
}
private DataSourceInitializer getDataSourceInit() {
DataSourceInitializer dsi = new DataSourceInitializer();
dsi.setDatabasePopulator(getDatabasePopulator());
dsi.setDataSource(this.dataSource);
return dsi;
}
}
在实例构造上进一步限制了父类中的U userDetailsService的类型为JdbcUserDetailsManager。
JdbcUserDetailsManager的继承关系图:

3.6 InMemoryUserDetailsManagerConfigurer
InMemoryUserDetailsManagerConfigurer继承了UserDetailsManagerConfigurer,在实例构造上进一步限制了父类中的U userDetailsService的类型为InMemoryUserDetailsManager。
/**
* Configures an
* {@link org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder}
* to have in memory authentication. It also allows easily adding users to the in memory
* authentication.
*
* @param <B> the type of the {@link ProviderManagerBuilder} that is being configured
* @author Rob Winch
* @since 3.2
*/
public class InMemoryUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>>
extends UserDetailsManagerConfigurer<B, InMemoryUserDetailsManagerConfigurer<B>> {
/**
* Creates a new instance
*/
public InMemoryUserDetailsManagerConfigurer() {
super(new InMemoryUserDetailsManager(new ArrayList<>()));
}
}
InMemoryUserDetailsManager的继承关系图:

3.7 使用示例
3.7.1 InMemoryUserDetailsManagerConfigurer 使用
@Configuration
public class BaseAuthenticationConfig {
@Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("{noop}password").roles("USER").and()
.withUser("admin").password("{noop}password").roles("USER", "ADMIN");
}
}
3.7.2 JdbcUserDetailsManagerConfigurer 使用
@Configuration
public class BaseAuthenticationConfig {
@Autowired
DataSource dataSource;
@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource);
}
}
3.7.3 DaoAuthenticationConfigurer 使用
@Configuration
public class BaseAuthenticationConfig {
@Autowired
UserDetailsService userDetailsService;
@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
}
四、AbstractHttpConfigurer
从这个类名就能大概知道是和Http配置有关。
源码注释:
为在HttpSecurity上运行的SecurityConfigurer实例添加一个方便的基类。
/**
* Adds a convenient base class for {@link SecurityConfigurer} instances that operate on
* {@link HttpSecurity}.
*
* @author Rob Winch
*/
public abstract class AbstractHttpConfigurer<T extends AbstractHttpConfigurer<T, B>, B extends HttpSecurityBuilder<B>>
extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, B> {
private SecurityContextHolderStrategy securityContextHolderStrategy;
/**
* Disables the {@link AbstractHttpConfigurer} by removing it. After doing so a fresh
* version of the configuration can be applied.
* @return the {@link HttpSecurityBuilder} for additional customizations
*/
@SuppressWarnings("unchecked")
public B disable() {
getBuilder().removeConfigurer(getClass());
return getBuilder();
}
@SuppressWarnings("unchecked")
public T withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
addObjectPostProcessor(objectPostProcessor);
return (T) this;
}
protected SecurityContextHolderStrategy getSecurityContextHolderStrategy() {
if (this.securityContextHolderStrategy != null) {
return this.securityContextHolderStrategy;
}
ApplicationContext context = getBuilder().getSharedObject(ApplicationContext.class);
String[] names = context.getBeanNamesForType(SecurityContextHolderStrategy.class);
if (names.length == 1) {
this.securityContextHolderStrategy = context.getBean(SecurityContextHolderStrategy.class);
}
else {
this.securityContextHolderStrategy = SecurityContextHolder.getContextHolderStrategy();
}
return this.securityContextHolderStrategy;
}
}
AbstractHttpConfigurer是一个抽象类,继承了SecurityConfigurerAdapter,是模版模式,通过源码我们可知:
-
继承
SecurityConfigurerAdapter时限制了父类的构建对象类型为:DefaultSecurityFilterChain。 -
泛型
B继承了HttpSecurityBuilder接口,HttpSecurityBuilder构造器的作用是用来构建DefaultSecurityFilterChain对象,可就意味AbstractHttpConfigurer(配置器)用来配置HttpSecurityBuilder构造器。 -
disable()方法通过移除configurer来实现禁用某配置器。 -
withObjectPostProcessor()方法为配置器手动添加后置处理器。 -
getSecurityContextHolderStrategy()方法获取SecurityContextHolder的使用策略。
我们来看下AbstractHttpConfigurer子类:

过滤器的配置都在这里面,我们可通过修改配置来实现自定义业务扩展。
下文我们着重分析下
AbstractAuthenticationFilterConfigurer和FormLoginConfigurer,其他子类实现在后续的业务实战章节我们再逐个进行分析。
4.1 AbstractAuthenticationFilterConfigurer
源码注释:
用于配置AbstractAuthenticationFilterConfigurer的基类。 这仅供内部使用。
/**
* Base class for configuring {@link AbstractAuthenticationFilterConfigurer}. This is
* intended for internal use only.
*
* @param <T> refers to "this" for returning the current configurer
* @param <F> refers to the {@link AbstractAuthenticationProcessingFilter} that is being
* built
* @author Rob Winch
* @since 3.2
* @see FormLoginConfigurer
*/
public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecurityBuilder<B>, T extends AbstractAuthenticationFilterConfigurer<B, T, F>, F extends AbstractAuthenticationProcessingFilter>
extends AbstractHttpConfigurer<T, B> {
private F authFilter;
private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource;
private SavedRequestAwareAuthenticationSuccessHandler defaultSuccessHandler = new SavedRequestAwareAuthenticationSuccessHandler();
private AuthenticationSuccessHandler successHandler = this.defaultSuccessHandler;
private LoginUrlAuthenticationEntryPoint authenticationEntryPoint;
private boolean customLoginPage;
private String loginPage;
private String loginProcessingUrl;
private AuthenticationFailureHandler failureHandler;
private boolean permitAll;
private String failureUrl;
/**
* Creates a new instance with minimal defaults
*/
protected AbstractAuthenticationFilterConfigurer() {
setLoginPage("/login");
}
/**
* Creates a new instance
* @param authenticationFilter the {@link AbstractAuthenticationProcessingFilter} to
* use
* @param defaultLoginProcessingUrl the default URL to use for
* {@link #loginProcessingUrl(String)}
*/
protected AbstractAuthenticationFilterConfigurer(F authenticationFilter, String defaultLoginProcessingUrl) {
this();
this.authFilter = authenticationFilter;
if (defaultLoginProcessingUrl != null) {
loginProcessingUrl(defaultLoginProcessingUrl);
}
}
/**
* Specifies where users will be redirected after authenticating successfully if they
* have not visited a secured page prior to authenticating. This is a shortcut for
* calling {@link #defaultSuccessUrl(String, boolean)}.
* @param defaultSuccessUrl the default success url
* @return the {@link FormLoginConfigurer} for additional customization
*/
public final T defaultSuccessUrl(String defaultSuccessUrl) {
return defaultSuccessUrl(defaultSuccessUrl, false);
}
/**
* Specifies where users will be redirected after authenticating successfully if they
* have not visited a secured page prior to authenticating or {@code alwaysUse} is
* true. This is a shortcut for calling
* {@link #successHandler(AuthenticationSuccessHandler)}.
* @param defaultSuccessUrl the default success url
* @param alwaysUse true if the {@code defaultSuccessUrl} should be used after
* authentication despite if a protected page had been previously visited
* @return the {@link FormLoginConfigurer} for additional customization
*/
public final T defaultSuccessUrl(String defaultSuccessUrl, boolean alwaysUse) {
SavedRequestAwareAuthenticationSuccessHandler handler = new SavedRequestAwareAuthenticationSuccessHandler();
handler.setDefaultTargetUrl(defaultSuccessUrl);
handler.setAlwaysUseDefaultTargetUrl(alwaysUse);
this.defaultSuccessHandler = handler;
return successHandler(handler);
}
/**
* Specifies the URL to validate the credentials.
* @param loginProcessingUrl the URL to validate username and password
* @return the {@link FormLoginConfigurer} for additional customization
*/
public T loginProcessingUrl(String loginProcessingUrl) {
this.loginProcessingUrl = loginProcessingUrl;
this.authFilter.setRequiresAuthenticationRequestMatcher(createLoginProcessingUrlMatcher(loginProcessingUrl));
return getSelf();
}
public T securityContextRepository(SecurityContextRepository securityContextRepository) {
this.authFilter.setSecurityContextRepository(securityContextRepository);
return getSelf();
}
/**
* Create the {@link RequestMatcher} given a loginProcessingUrl
* @param loginProcessingUrl creates the {@link RequestMatcher} based upon the
* loginProcessingUrl
* @return the {@link RequestMatcher} to use based upon the loginProcessingUrl
*/
protected abstract RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl);
/**
* Specifies a custom {@link AuthenticationDetailsSource}. The default is
* {@link WebAuthenticationDetailsSource}.
* @param authenticationDetailsSource the custom {@link AuthenticationDetailsSource}
* @return the {@link FormLoginConfigurer} for additional customization
*/
public final T authenticationDetailsSource(
AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource) {
this.authenticationDetailsSource = authenticationDetailsSource;
return getSelf();
}
/**
* Specifies the {@link AuthenticationSuccessHandler} to be used. The default is
* {@link SavedRequestAwareAuthenticationSuccessHandler} with no additional properties
* set.
* @param successHandler the {@link AuthenticationSuccessHandler}.
* @return the {@link FormLoginConfigurer} for additional customization
*/
public final T successHandler(AuthenticationSuccessHandler successHandler) {
this.successHandler = successHandler;
return getSelf();
}
/**
* Equivalent of invoking permitAll(true)
* @return the {@link FormLoginConfigurer} for additional customization
*/
public final T permitAll() {
return permitAll(true);
}
/**
* Ensures the urls for {@link #failureUrl(String)} as well as for the
* {@link HttpSecurityBuilder}, the {@link #getLoginPage} and
* {@link #getLoginProcessingUrl} are granted access to any user.
* @param permitAll true to grant access to the URLs false to skip this step
* @return the {@link FormLoginConfigurer} for additional customization
*/
public final T permitAll(boolean permitAll) {
this.permitAll = permitAll;
return getSelf();
}
/**
* The URL to send users if authentication fails. This is a shortcut for invoking
* {@link #failureHandler(AuthenticationFailureHandler)}. The default is
* "/login?error".
* @param authenticationFailureUrl the URL to send users if authentication fails (i.e.
* "/login?error").
* @return the {@link FormLoginConfigurer} for additional customization
*/
public final T failureUrl(String authenticationFailureUrl) {
T result = failureHandler(new SimpleUrlAuthenticationFailureHandler(authenticationFailureUrl));
this.failureUrl = authenticationFailureUrl;
return result;
}
/**
* Specifies the {@link AuthenticationFailureHandler} to use when authentication
* fails. The default is redirecting to "/login?error" using
* {@link SimpleUrlAuthenticationFailureHandler}
* @param authenticationFailureHandler the {@link AuthenticationFailureHandler} to use
* when authentication fails.
* @return the {@link FormLoginConfigurer} for additional customization
*/
public final T failureHandler(AuthenticationFailureHandler authenticationFailureHandler) {
this.failureUrl = null;
this.failureHandler = authenticationFailureHandler;
return getSelf();
}
@Override
public void init(B http) throws Exception {
updateAuthenticationDefaults();
updateAccessDefaults(http);
registerDefaultAuthenticationEntryPoint(http);
}
@SuppressWarnings("unchecked")
protected final void registerDefaultAuthenticationEntryPoint(B http) {
registerAuthenticationEntryPoint(http, this.authenticationEntryPoint);
}
@SuppressWarnings("unchecked")
protected final void registerAuthenticationEntryPoint(B http, AuthenticationEntryPoint authenticationEntryPoint) {
ExceptionHandlingConfigurer<B> exceptionHandling = http.getConfigurer(ExceptionHandlingConfigurer.class);
if (exceptionHandling == null) {
return;
}
exceptionHandling.defaultAuthenticationEntryPointFor(postProcess(authenticationEntryPoint),
getAuthenticationEntryPointMatcher(http));
}
protected final RequestMatcher getAuthenticationEntryPointMatcher(B http) {
ContentNegotiationStrategy contentNegotiationStrategy = http.getSharedObject(ContentNegotiationStrategy.class);
if (contentNegotiationStrategy == null) {
contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
}
MediaTypeRequestMatcher mediaMatcher = new MediaTypeRequestMatcher(contentNegotiationStrategy,
MediaType.APPLICATION_XHTML_XML, new MediaType("image", "*"), MediaType.TEXT_HTML,
MediaType.TEXT_PLAIN);
mediaMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
RequestMatcher notXRequestedWith = new NegatedRequestMatcher(
new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest"));
return new AndRequestMatcher(Arrays.asList(notXRequestedWith, mediaMatcher));
}
@Override
public void configure(B http) throws Exception {
PortMapper portMapper = http.getSharedObject(PortMapper.class);
if (portMapper != null) {
this.authenticationEntryPoint.setPortMapper(portMapper);
}
RequestCache requestCache = http.getSharedObject(RequestCache.class);
if (requestCache != null) {
this.defaultSuccessHandler.setRequestCache(requestCache);
}
this.authFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
this.authFilter.setAuthenticationSuccessHandler(this.successHandler);
this.authFilter.setAuthenticationFailureHandler(this.failureHandler);
if (this.authenticationDetailsSource != null) {
this.authFilter.setAuthenticationDetailsSource(this.authenticationDetailsSource);
}
SessionAuthenticationStrategy sessionAuthenticationStrategy = http
.getSharedObject(SessionAuthenticationStrategy.class);
if (sessionAuthenticationStrategy != null) {
this.authFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
}
RememberMeServices rememberMeServices = http.getSharedObject(RememberMeServices.class);
if (rememberMeServices != null) {
this.authFilter.setRememberMeServices(rememberMeServices);
}
SecurityContextConfigurer securityContextConfigurer = http.getConfigurer(SecurityContextConfigurer.class);
if (securityContextConfigurer != null && securityContextConfigurer.isRequireExplicitSave()) {
SecurityContextRepository securityContextRepository = securityContextConfigurer
.getSecurityContextRepository();
this.authFilter.setSecurityContextRepository(securityContextRepository);
}
this.authFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
F filter = postProcess(this.authFilter);
http.addFilter(filter);
}
/**
* <p>
* Specifies the URL to send users to if login is required. If used with
* {@link EnableWebSecurity} a default login page will be generated when this
* attribute is not specified.
* </p>
*
* <p>
* If a URL is specified or this is not being used in conjunction with
* {@link EnableWebSecurity}, users are required to process the specified URL to
* generate a login page.
* </p>
*/
protected T loginPage(String loginPage) {
setLoginPage(loginPage);
updateAuthenticationDefaults();
this.customLoginPage = true;
return getSelf();
}
/**
* @return true if a custom login page has been specified, else false
*/
public final boolean isCustomLoginPage() {
return this.customLoginPage;
}
/**
* Gets the Authentication Filter
* @return the Authentication Filter
*/
protected final F getAuthenticationFilter() {
return this.authFilter;
}
/**
* Sets the Authentication Filter
* @param authFilter the Authentication Filter
*/
protected final void setAuthenticationFilter(F authFilter) {
this.authFilter = authFilter;
}
/**
* Gets the login page
* @return the login page
*/
protected final String getLoginPage() {
return this.loginPage;
}
/**
* Gets the Authentication Entry Point
* @return the Authentication Entry Point
*/
protected final AuthenticationEntryPoint getAuthenticationEntryPoint() {
return this.authenticationEntryPoint;
}
/**
* Gets the URL to submit an authentication request to (i.e. where username/password
* must be submitted)
* @return the URL to submit an authentication request to
*/
protected final String getLoginProcessingUrl() {
return this.loginProcessingUrl;
}
/**
* Gets the URL to send users to if authentication fails
* @return the URL to send users if authentication fails (e.g. "/login?error").
*/
protected final String getFailureUrl() {
return this.failureUrl;
}
/**
* Updates the default values for authentication.
*/
protected final void updateAuthenticationDefaults() {
if (this.loginProcessingUrl == null) {
loginProcessingUrl(this.loginPage);
}
if (this.failureHandler == null) {
failureUrl(this.loginPage + "?error");
}
LogoutConfigurer<B> logoutConfigurer = getBuilder().getConfigurer(LogoutConfigurer.class);
if (logoutConfigurer != null && !logoutConfigurer.isCustomLogoutSuccess()) {
logoutConfigurer.logoutSuccessUrl(this.loginPage + "?logout");
}
}
/**
* Updates the default values for access.
*/
protected final void updateAccessDefaults(B http) {
if (this.permitAll) {
PermitAllSupport.permitAll(http, this.loginPage, this.loginProcessingUrl, this.failureUrl);
}
}
/**
* Sets the loginPage and updates the {@link AuthenticationEntryPoint}.
* @param loginPage
*/
private void setLoginPage(String loginPage) {
this.loginPage = loginPage;
this.authenticationEntryPoint = new LoginUrlAuthenticationEntryPoint(loginPage);
}
@SuppressWarnings("unchecked")
private T getSelf() {
return (T) this;
}
}
AbstractAuthenticationFilterConfigurer也是一个抽象类,继承了AbstractHttpConfigurer,是模版模式,通过源码我们可知:
- 泛型
F继承了AbstractAuthenticationProcessingFilter抽象类,而AbstractAuthenticationProcessingFilter
继承了GenericFilterBean,意味着F是一个过滤器。
AbstractAuthenticationFilterConfigurer作为配置器,我们只需抓住init方法和configure方法这两个核心即可:
查看init方法:
@Override
public void init(B http) throws Exception {
updateAuthenticationDefaults();
updateAccessDefaults(http);
registerDefaultAuthenticationEntryPoint(http);
}
init方法主要干了三件事:
updateAuthenticationDefaults方法更新身份认证的默认值(包括:登录页面、失败处理、登出配置)。updateAccessDefaults方法更新默认放行的访问控制。registerDefaultAuthenticationEntryPoint方法注册默认身份认证端点(未认证处理)。
查看configure方法:
@Override
public void configure(B http) throws Exception {
PortMapper portMapper = http.getSharedObject(PortMapper.class);
if (portMapper != null) {
this.authenticationEntryPoint.setPortMapper(portMapper);
}
RequestCache requestCache = http.getSharedObject(RequestCache.class);
if (requestCache != null) {
this.defaultSuccessHandler.setRequestCache(requestCache);
}
this.authFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
this.authFilter.setAuthenticationSuccessHandler(this.successHandler);
this.authFilter.setAuthenticationFailureHandler(this.failureHandler);
if (this.authenticationDetailsSource != null) {
this.authFilter.setAuthenticationDetailsSource(this.authenticationDetailsSource);
}
SessionAuthenticationStrategy sessionAuthenticationStrategy = http
.getSharedObject(SessionAuthenticationStrategy.class);
if (sessionAuthenticationStrategy != null) {
this.authFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
}
RememberMeServices rememberMeServices = http.getSharedObject(RememberMeServices.class);
if (rememberMeServices != null) {
this.authFilter.setRememberMeServices(rememberMeServices);
}
SecurityContextConfigurer securityContextConfigurer = http.getConfigurer(SecurityContextConfigurer.class);
if (securityContextConfigurer != null && securityContextConfigurer.isRequireExplicitSave()) {
SecurityContextRepository securityContextRepository = securityContextConfigurer
.getSecurityContextRepository();
this.authFilter.setSecurityContextRepository(securityContextRepository);
}
this.authFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
F filter = postProcess(this.authFilter);
http.addFilter(filter);
}
configure方法逻辑就比较简单了:构建各种各样的回调函数设置给 authFilter,authFilter再去 postProcess中走一圈注册到Spring Ioc容器中,最后再把authFilter添加到过滤器链中。
authFilter来自子类调用父类AbstractAuthenticationFilterConfigurer的构造方法进行赋值。
4.2 FormLoginConfigurer
FormLoginConfigurer在继承AbstractAuthenticationFilterConfigurer时限定了父类泛型F是 UsernamePasswordAuthenticationFilter类型,也就意味着我们这里最终要配置的过滤是 UsernamePasswordAuthenticationFilter。
FormLoginConfigurer重写了init方法,配置了一下默认的登录页面。其他的基本上都是从父类来的,未做太多改变。
源码注释:
添加基于表单的身份认证。 所有属性都有合理的默认值,使得所有参数都是可选的。 如果未指定loginPage(String),框架将生成默认登录页面。
public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractAuthenticationFilterConfigurer<H, FormLoginConfigurer<H>, UsernamePasswordAuthenticationFilter> {
/**
* Creates a new instance
* @see HttpSecurity#formLogin()
*/
public FormLoginConfigurer() {
super(new UsernamePasswordAuthenticationFilter(), null);
usernameParameter("username");
passwordParameter("password");
}
/**
* <p>
* Specifies the URL to send users to if login is required. If used with
* {@link EnableWebSecurity} a default login page will be generated when this
* attribute is not specified.
* </p>
*
* <p>
* If a URL is specified or this is not being used in conjunction with
* {@link EnableWebSecurity}, users are required to process the specified URL to
* generate a login page. In general, the login page should create a form that submits
* a request with the following requirements to work with
* {@link UsernamePasswordAuthenticationFilter}:
* </p>
*
* <ul>
* <li>It must be an HTTP POST</li>
* <li>It must be submitted to {@link #loginProcessingUrl(String)}</li>
* <li>It should include the username as an HTTP parameter by the name of
* {@link #usernameParameter(String)}</li>
* <li>It should include the password as an HTTP parameter by the name of
* {@link #passwordParameter(String)}</li>
* </ul>
*
* <h2>Example login.jsp</h2>
*
* Login pages can be rendered with any technology you choose so long as the rules
* above are followed. Below is an example login.jsp that can be used as a quick start
* when using JSP's or as a baseline to translate into another view technology.
*
* <pre>
* <!-- loginProcessingUrl should correspond to FormLoginConfigurer#loginProcessingUrl. Don't forget to perform a POST -->
* <c:url value="/login" var="loginProcessingUrl"/>
* <form action="${loginProcessingUrl}" method="post">
* <fieldset>
* <legend>Please Login</legend>
* <!-- use param.error assuming FormLoginConfigurer#failureUrl contains the query parameter error -->
* <c:if test="${param.error != null}">
* <div>
* Failed to login.
* <c:if test="${SPRING_SECURITY_LAST_EXCEPTION != null}">
* Reason: <c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}" />
* </c:if>
* </div>
* </c:if>
* <!-- the configured LogoutConfigurer#logoutSuccessUrl is /login?logout and contains the query param logout -->
* <c:if test="${param.logout != null}">
* <div>
* You have been logged out.
* </div>
* </c:if>
* <p>
* <label for="username">Username</label>
* <input type="text" id="username" name="username"/>
* </p>
* <p>
* <label for="password">Password</label>
* <input type="password" id="password" name="password"/>
* </p>
* <!-- if using RememberMeConfigurer make sure remember-me matches RememberMeConfigurer#rememberMeParameter -->
* <p>
* <label for="remember-me">Remember Me?</label>
* <input type="checkbox" id="remember-me" name="remember-me"/>
* </p>
* <div>
* <button type="submit" class="btn">Log in</button>
* </div>
* </fieldset>
* </form>
* </pre>
*
* <h2>Impact on other defaults</h2>
*
* Updating this value, also impacts a number of other default values. For example,
* the following are the default values when only formLogin() was specified.
*
* <ul>
* <li>/login GET - the login form</li>
* <li>/login POST - process the credentials and if valid authenticate the user</li>
* <li>/login?error GET - redirect here for failed authentication attempts</li>
* <li>/login?logout GET - redirect here after successfully logging out</li>
* </ul>
*
* If "/authenticate" was passed to this method it update the defaults as shown below:
*
* <ul>
* <li>/authenticate GET - the login form</li>
* <li>/authenticate POST - process the credentials and if valid authenticate the user
* </li>
* <li>/authenticate?error GET - redirect here for failed authentication attempts</li>
* <li>/authenticate?logout GET - redirect here after successfully logging out</li>
* </ul>
* @param loginPage the login page to redirect to if authentication is required (i.e.
* "/login")
* @return the {@link FormLoginConfigurer} for additional customization
*/
@Override
public FormLoginConfigurer<H> loginPage(String loginPage) {
return super.loginPage(loginPage);
}
/**
* The HTTP parameter to look for the username when performing authentication. Default
* is "username".
* @param usernameParameter the HTTP parameter to look for the username when
* performing authentication
* @return the {@link FormLoginConfigurer} for additional customization
*/
public FormLoginConfigurer<H> usernameParameter(String usernameParameter) {
getAuthenticationFilter().setUsernameParameter(usernameParameter);
return this;
}
/**
* The HTTP parameter to look for the password when performing authentication. Default
* is "password".
* @param passwordParameter the HTTP parameter to look for the password when
* performing authentication
* @return the {@link FormLoginConfigurer} for additional customization
*/
public FormLoginConfigurer<H> passwordParameter(String passwordParameter) {
getAuthenticationFilter().setPasswordParameter(passwordParameter);
return this;
}
/**
* Forward Authentication Failure Handler
* @param forwardUrl the target URL in case of failure
* @return the {@link FormLoginConfigurer} for additional customization
*/
public FormLoginConfigurer<H> failureForwardUrl(String forwardUrl) {
failureHandler(new ForwardAuthenticationFailureHandler(forwardUrl));
return this;
}
/**
* Forward Authentication Success Handler
* @param forwardUrl the target URL in case of success
* @return the {@link FormLoginConfigurer} for additional customization
*/
public FormLoginConfigurer<H> successForwardUrl(String forwardUrl) {
successHandler(new ForwardAuthenticationSuccessHandler(forwardUrl));
return this;
}
@Override
public void init(H http) throws Exception {
super.init(http);
initDefaultLoginFilter(http);
}
@Override
protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
return new AntPathRequestMatcher(loginProcessingUrl, "POST");
}
/**
* Gets the HTTP parameter that is used to submit the username.
* @return the HTTP parameter that is used to submit the username
*/
private String getUsernameParameter() {
return getAuthenticationFilter().getUsernameParameter();
}
/**
* Gets the HTTP parameter that is used to submit the password.
* @return the HTTP parameter that is used to submit the password
*/
private String getPasswordParameter() {
return getAuthenticationFilter().getPasswordParameter();
}
/**
* If available, initializes the {@link DefaultLoginPageGeneratingFilter} shared
* object.
* @param http the {@link HttpSecurityBuilder} to use
*/
private void initDefaultLoginFilter(H http) {
DefaultLoginPageGeneratingFilter loginPageGeneratingFilter = http
.getSharedObject(DefaultLoginPageGeneratingFilter.class);
if (loginPageGeneratingFilter != null && !isCustomLoginPage()) {
loginPageGeneratingFilter.setFormLoginEnabled(true);
loginPageGeneratingFilter.setUsernameParameter(getUsernameParameter());
loginPageGeneratingFilter.setPasswordParameter(getPasswordParameter());
loginPageGeneratingFilter.setLoginPageUrl(getLoginPage());
loginPageGeneratingFilter.setFailureUrl(getFailureUrl());
loginPageGeneratingFilter.setAuthenticationUrl(getLoginProcessingUrl());
}
}
}
另外我们日常配置的很多东西也是来自这里:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!