跳到主要内容

用户名/密码认证

QWen Max 中英对照 Username/Password Username/Password Authentication

最常用的用户认证方式之一是验证用户名和密码。Spring Security 为使用用户名和密码进行认证提供了全面的支持。

您可以使用以下方法配置用户名和密码身份验证:

@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);
}

}
java

上述配置会自动向 SecurityFilterChain 注册一个内存中的 UserDetailsService,将 DaoAuthenticationProvider 注册到默认的 AuthenticationManager,并启用 表单登录HTTP Basic 身份验证。

要了解更多关于用户名/密码认证的信息,请考虑以下用例:

发布一个 AuthenticationManager bean

一个相当常见的需求是发布一个 AuthenticationManager bean,以便在 @Service 或 Spring MVC 的 @Controller 中进行自定义认证。例如,你可能希望通过 REST API 而不是使用表单登录来认证用户。

您可以使用以下配置为自定义身份验证场景发布此类 AuthenticationManager

@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();
}

}
java

有了上述配置,你可以创建一个使用 AuthenticationManager@RestController,如下所示:

@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) {
}

}
java
备注

在本示例中,如果需要,您有责任将已认证的用户保存在 SecurityContextRepository 中。例如,如果使用 HttpSession 在请求之间持久化 SecurityContext,您可以使用 HttpSessionSecurityContextRepository

自定义 AuthenticationManager

通常,Spring Security 会内部构建一个 AuthenticationManager,其中包含一个用于用户名/密码认证的 DaoAuthenticationProvider。在某些情况下,可能仍然需要自定义 Spring Security 使用的 AuthenticationManager 实例。例如,你可能需要简单地禁用缓存用户的凭证擦除

要做到这一点,你可以利用这样一个事实:用于构建 Spring Security 的全局 AuthenticationManagerAuthenticationManagerBuilder 会被发布为一个 bean。你可以按如下方式配置该构建器:

@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);
}

}
java

或者,你可以配置一个本地的 AuthenticationManager 来覆盖全局的 AuthenticationManager

@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())
.authenticationManager(authenticationManager());

return http.build();
}

private AuthenticationManager authenticationManager() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService());
authenticationProvider.setPasswordEncoder(passwordEncoder());

ProviderManager providerManager = new ProviderManager(authenticationProvider);
providerManager.setEraseCredentialsAfterAuthentication(false);

return providerManager;
}

private UserDetailsService userDetailsService() {
UserDetails userDetails = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();

return new InMemoryUserDetailsManager(userDetails);
}

private PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}

}
java

章节摘要