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 小时前
基于SpringBoot的公益基金管理系统(源码+文档+讲解视频)
java·spring boot·后端
东小西1 小时前
【SAA实战】第 3 篇 · 工具调用全攻略:把业务能力交给 Agent 自己调度
java·后端·spring
东小西1 小时前
【SAA实战】第 4 篇 · Agent 短期记忆:saver 让 Agent 跨轮记得住(threadId 隔离)
java·后端·spring
许彰午2 小时前
22-DataCenter报文序列化
java·低代码·架构·状态模式
2601_962065252 小时前
[MySQL] SQL优化之性能分析
java·sql·mysql
阿kun要赚马内2 小时前
MySQL 索引基础
后端·mysql
小范同学_2 小时前
JDK1.7 与 JDK1.8 HashMap 底层原理对比 + 数组并发扩容死循环详解
java·开发语言
码事漫谈2 小时前
我啥都能做,却不知道做什么了
后端
geovindu3 小时前
CSharp: 万年历
开发语言·后端·c#·.net
予昊3 小时前
从零实现“在线五子棋对战“:WebSocket 实时通信 + 段位匹配
java·开发语言·网络·websocket