SpringSecurity中文文档(UsernamePassword Authentication)

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 基本认证。

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

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

}
相关推荐
老李头喽1 天前
走进单元测试
java·单元测试
就叫飞六吧1 天前
Spring MVC 接口命名为什么会有 *.do/actions等身影?
java·spring·mvc
Victor3561 天前
Redis(154)Redis的数据一致性如何保证?
后端
葡萄成熟时 !1 天前
黑马学生管理系统
java·开发语言
r***86981 天前
springboot三层架构详细讲解
spring boot·后端·架构
Victor3561 天前
Redis(155)Redis的数据持久化如何优化?
后端
许泽宇的技术分享1 天前
AgentFramework-零基础入门-第08章_部署和监控代理
人工智能·后端·agent框架·agentframework
h***67371 天前
springboot中配置logback-spring.xml
spring boot·spring·logback
沐浴露z1 天前
为什么使用SpringAI时通常用Builder来创建对象?详解 【Builder模式】和【直接 new】的区别
java·python·建造者模式
阿杰真不会敲代码1 天前
Filter与Interceptor深度解析:分清这两个“拦截器”,面试不再掉坑
java·spring boot·面试