Username/Password Authentication
验证用户的最常见方法之一是验证用户名和密码。SpringSecurity 为使用用户名和密码进行身份验证提供了全面的支持。
您可以使用以下方法配置用户名和密码身份验证:
Simple Username/Password Example
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.httpBasic(Customizer.withDefaults())
.formLogin(Customizer.withDefaults());
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails userDetails = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(userDetails);
}
}
前面的配置自动在 SecurityFilterChain 中注册了一个内存中的 UserDetailsService,将 DaoAuthenticationProvider 注册到默认的 AuthenticationManager,并启用了表单登录和 HTTP 基本认证。
要了解更多关于用户名/密码身份验证的信息,请考虑以下用例:
- I want to learn how Form Login works
- I want to learn how HTTP Basic authentication works
- I want to learn how
DaoAuthenticationProvider
works - I want to manage users in memory
- I want to manage users in a database
- I want to manage users in LDAP
- I want to publish an
AuthenticationManager
bean for custom authentication - I want to customize the global
AuthenticationManager
Publish an AuthenticationManager
bean
一个相当常见的需求是发布一个 AuthenticationManager bean,以允许进行自定义认证,例如在 @Service 或 Spring MVC @Controller 中。例如,您可能希望通过 REST API 认证用户,而不是使用表单登录。
您可以使用以下配置为自定义身份验证方案发布这样的 AuthenticationManager:
Publish AuthenticationManager
bean for Custom Authentication
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/login").permitAll()
.anyRequest().authenticated()
);
return http.build();
}
@Bean
public AuthenticationManager authenticationManager(
UserDetailsService userDetailsService,
PasswordEncoder passwordEncoder) {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder);
return new ProviderManager(authenticationProvider);
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails userDetails = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(userDetails);
}
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
}
有了前面的配置,您可以创建一个@RestController,它使用 AuthenticationManager,如下所示:
Create a @RestController
for Authentication
java
@RestController
public class LoginController {
private final AuthenticationManager authenticationManager;
public LoginController(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@PostMapping("/login")
public ResponseEntity<Void> login(@RequestBody LoginRequest loginRequest) {
Authentication authenticationRequest =
UsernamePasswordAuthenticationToken.unauthenticated(loginRequest.username(), loginRequest.password());
Authentication authenticationResponse =
this.authenticationManager.authenticate(authenticationRequest);
// ...
}
public record LoginRequest(String username, String password) {
}
}
在本例中,如果需要,您有责任将经过身份验证的用户保存在 SecurityContextRepository 中。例如,如果使用 HttpSession 在请求之间保持 SecurityContext,则可以使用 HttpSessionSecurityContextRepository。
Customize the AuthenticationManager
通常,Spring Security 内部构建一个由 DaoAuthenticationProvider 组成的 AuthenticationManager,用于用户名/密码认证。在某些情况下,可能仍然需要自定义 Spring Security 使用的 AuthenticationManager 实例。例如,您可能需要简单地禁用缓存用户的凭据擦除。
推荐的方法是简单地发布您自己的 AuthenticationManagerbean,SpringSecurity 将使用它。您可以使用以下配置发布 AuthenticationManager:
Publish AuthenticationManager
bean for Spring Security
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authorize) -> authorize
.requestMatchers("/login").permitAll()
.anyRequest().authenticated()
)
.httpBasic(Customizer.withDefaults())
.formLogin(Customizer.withDefaults());
return http.build();
}
@Bean
public AuthenticationManager authenticationManager(
UserDetailsService userDetailsService,
PasswordEncoder passwordEncoder) {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder);
ProviderManager providerManager = new ProviderManager(authenticationProvider);
providerManager.setEraseCredentialsAfterAuthentication(false);
return providerManager;
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails userDetails = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(userDetails);
}
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
}
或者,您可以利用这样一个事实,即用于构建 Spring Security 的全局 AuthenticationManager 的 AuthenticationManagerBuilder 是作为 bean 发布的。可以按以下方式配置生成器:
Configure global AuthenticationManagerBuilder
java
@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);
}
}