|
@@ -326,10 +326,74 @@ Normally, Spring Security builds an `AuthenticationManager` internally composed
|
|
|
In certain cases, it may still be desired to customize the instance of `AuthenticationManager` used by Spring Security.
|
|
|
For example, you may need to simply disable xref:servlet/authentication/architecture.adoc#servlet-authentication-providermanager-erasing-credentials[credential erasure] for cached users.
|
|
|
|
|
|
-The recommended way to do this is to simply publish your own `AuthenticationManager` bean, and Spring Security will use it.
|
|
|
-You can publish an `AuthenticationManager` using the following configuration:
|
|
|
+To do this, you can take advantage of the fact that the `AuthenticationManagerBuilder` used to build Spring Security's global `AuthenticationManager` is published as a bean.
|
|
|
+You can configure the builder as follows:
|
|
|
+
|
|
|
+.Configure global `AuthenticationManagerBuilder`
|
|
|
+[tabs]
|
|
|
+=====
|
|
|
+Java::
|
|
|
++
|
|
|
+[source,java,role="primary"]
|
|
|
+----
|
|
|
+@Configuration
|
|
|
+@EnableWebSecurity
|
|
|
+public class SecurityConfig {
|
|
|
+
|
|
|
+ @Bean
|
|
|
+ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
|
|
+ // ...
|
|
|
+ return http.build();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Bean
|
|
|
+ public UserDetailsService userDetailsService() {
|
|
|
+ // Return a UserDetailsService that caches users
|
|
|
+ // ...
|
|
|
+ }
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ public void configure(AuthenticationManagerBuilder builder) {
|
|
|
+ builder.eraseCredentials(false);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+----
|
|
|
+
|
|
|
+Kotlin::
|
|
|
++
|
|
|
+[source,kotlin,role="secondary"]
|
|
|
+----
|
|
|
+import org.springframework.security.config.annotation.web.invoke
|
|
|
|
|
|
-.Publish `AuthenticationManager` bean for Spring Security
|
|
|
+@Configuration
|
|
|
+@EnableWebSecurity
|
|
|
+class SecurityConfig {
|
|
|
+
|
|
|
+ @Bean
|
|
|
+ fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
|
|
+ // ...
|
|
|
+ return http.build()
|
|
|
+ }
|
|
|
+
|
|
|
+ @Bean
|
|
|
+ fun userDetailsService(): UserDetailsService {
|
|
|
+ // Return a UserDetailsService that caches users
|
|
|
+ // ...
|
|
|
+ }
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ fun configure(builder: AuthenticationManagerBuilder) {
|
|
|
+ builder.eraseCredentials(false)
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+----
|
|
|
+=====
|
|
|
+
|
|
|
+Alternatively, you may configure a local `AuthenticationManager` to override the global one.
|
|
|
+
|
|
|
+.Configure local `AuthenticationManager` for Spring Security
|
|
|
[tabs]
|
|
|
=====
|
|
|
Java::
|
|
@@ -344,22 +408,19 @@ public class SecurityConfig {
|
|
|
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
|
|
http
|
|
|
.authorizeHttpRequests((authorize) -> authorize
|
|
|
- .requestMatchers("/login").permitAll()
|
|
|
.anyRequest().authenticated()
|
|
|
)
|
|
|
.httpBasic(Customizer.withDefaults())
|
|
|
- .formLogin(Customizer.withDefaults());
|
|
|
+ .formLogin(Customizer.withDefaults())
|
|
|
+ .authenticationManager(authenticationManager());
|
|
|
|
|
|
return http.build();
|
|
|
}
|
|
|
|
|
|
- @Bean
|
|
|
- public AuthenticationManager authenticationManager(
|
|
|
- UserDetailsService userDetailsService,
|
|
|
- PasswordEncoder passwordEncoder) {
|
|
|
+ private AuthenticationManager authenticationManager() {
|
|
|
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
|
|
|
- authenticationProvider.setUserDetailsService(userDetailsService);
|
|
|
- authenticationProvider.setPasswordEncoder(passwordEncoder);
|
|
|
+ authenticationProvider.setUserDetailsService(userDetailsService());
|
|
|
+ authenticationProvider.setPasswordEncoder(passwordEncoder());
|
|
|
|
|
|
ProviderManager providerManager = new ProviderManager(authenticationProvider);
|
|
|
providerManager.setEraseCredentialsAfterAuthentication(false);
|
|
@@ -367,8 +428,7 @@ public class SecurityConfig {
|
|
|
return providerManager;
|
|
|
}
|
|
|
|
|
|
- @Bean
|
|
|
- public UserDetailsService userDetailsService() {
|
|
|
+ private UserDetailsService userDetailsService() {
|
|
|
UserDetails userDetails = User.withDefaultPasswordEncoder()
|
|
|
.username("user")
|
|
|
.password("password")
|
|
@@ -378,8 +438,7 @@ public class SecurityConfig {
|
|
|
return new InMemoryUserDetailsManager(userDetails);
|
|
|
}
|
|
|
|
|
|
- @Bean
|
|
|
- public PasswordEncoder passwordEncoder() {
|
|
|
+ private PasswordEncoder passwordEncoder() {
|
|
|
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
|
|
|
}
|
|
|
|
|
@@ -390,8 +449,7 @@ XML::
|
|
|
+
|
|
|
[source,xml,role="secondary"]
|
|
|
----
|
|
|
-<http>
|
|
|
- <intercept-url pattern="/login" access="permitAll"/>
|
|
|
+<http authentication-manager-ref="authenticationManager">
|
|
|
<intercept-url pattern="/**" access="authenticated"/>
|
|
|
<form-login />
|
|
|
<http-basic />
|
|
@@ -431,23 +489,21 @@ class SecurityConfig {
|
|
|
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
|
|
http {
|
|
|
authorizeHttpRequests {
|
|
|
- authorize("/login", permitAll)
|
|
|
authorize(anyRequest, authenticated)
|
|
|
}
|
|
|
formLogin { }
|
|
|
httpBasic { }
|
|
|
+ authenticationManager = authenticationManager()
|
|
|
}
|
|
|
|
|
|
return http.build()
|
|
|
}
|
|
|
|
|
|
@Bean
|
|
|
- fun authenticationManager(
|
|
|
- userDetailsService: UserDetailsService,
|
|
|
- passwordEncoder: PasswordEncoder): AuthenticationManager {
|
|
|
+ fun authenticationManager(): AuthenticationManager {
|
|
|
val authenticationProvider = DaoAuthenticationProvider()
|
|
|
- authenticationProvider.setUserDetailsService(userDetailsService)
|
|
|
- authenticationProvider.setPasswordEncoder(passwordEncoder)
|
|
|
+ authenticationProvider.setUserDetailsService(userDetailsService())
|
|
|
+ authenticationProvider.setPasswordEncoder(passwordEncoder())
|
|
|
|
|
|
val providerManager = ProviderManager(authenticationProvider)
|
|
|
providerManager.eraseCredentialsAfterAuthentication = false
|
|
@@ -455,8 +511,7 @@ class SecurityConfig {
|
|
|
return providerManager
|
|
|
}
|
|
|
|
|
|
- @Bean
|
|
|
- fun userDetailsService(): UserDetailsService {
|
|
|
+ private fun userDetailsService(): UserDetailsService {
|
|
|
val user = User.withDefaultPasswordEncoder()
|
|
|
.username("user")
|
|
|
.password("password")
|
|
@@ -466,8 +521,7 @@ class SecurityConfig {
|
|
|
return InMemoryUserDetailsManager(user)
|
|
|
}
|
|
|
|
|
|
- @Bean
|
|
|
- fun passwordEncoder(): PasswordEncoder {
|
|
|
+ private fun passwordEncoder(): PasswordEncoder {
|
|
|
return PasswordEncoderFactories.createDelegatingPasswordEncoder()
|
|
|
}
|
|
|
|
|
@@ -475,67 +529,3 @@ class SecurityConfig {
|
|
|
----
|
|
|
=====
|
|
|
|
|
|
-Alternatively, you can take advantage of the fact that the `AuthenticationManagerBuilder` used to build Spring Security's global `AuthenticationManager` is published as a bean.
|
|
|
-You can configure the builder as follows:
|
|
|
-
|
|
|
-.Configure global `AuthenticationManagerBuilder`
|
|
|
-[tabs]
|
|
|
-=====
|
|
|
-Java::
|
|
|
-+
|
|
|
-[source,java,role="primary"]
|
|
|
-----
|
|
|
-@Configuration
|
|
|
-@EnableWebSecurity
|
|
|
-public class SecurityConfig {
|
|
|
-
|
|
|
- @Bean
|
|
|
- public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
|
|
- // ...
|
|
|
- return http.build();
|
|
|
- }
|
|
|
-
|
|
|
- @Bean
|
|
|
- public UserDetailsService userDetailsService() {
|
|
|
- // Return a UserDetailsService that caches users
|
|
|
- // ...
|
|
|
- }
|
|
|
-
|
|
|
- @Autowired
|
|
|
- public void configure(AuthenticationManagerBuilder builder) {
|
|
|
- builder.eraseCredentials(false);
|
|
|
- }
|
|
|
-
|
|
|
-}
|
|
|
-----
|
|
|
-
|
|
|
-Kotlin::
|
|
|
-+
|
|
|
-[source,kotlin,role="secondary"]
|
|
|
-----
|
|
|
-import org.springframework.security.config.annotation.web.invoke
|
|
|
-
|
|
|
-@Configuration
|
|
|
-@EnableWebSecurity
|
|
|
-class SecurityConfig {
|
|
|
-
|
|
|
- @Bean
|
|
|
- fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
|
|
|
- // ...
|
|
|
- return http.build()
|
|
|
- }
|
|
|
-
|
|
|
- @Bean
|
|
|
- fun userDetailsService(): UserDetailsService {
|
|
|
- // Return a UserDetailsService that caches users
|
|
|
- // ...
|
|
|
- }
|
|
|
-
|
|
|
- @Autowired
|
|
|
- fun configure(builder: AuthenticationManagerBuilder) {
|
|
|
- builder.eraseCredentials(false)
|
|
|
- }
|
|
|
-
|
|
|
-}
|
|
|
-----
|
|
|
-=====
|