对于最新的稳定版本,请使用 Spring Security 6.4.1spring-doc.cadn.net.cn

用户名/密码身份验证

对用户进行身份验证的最常见方法之一是验证用户名和密码。 Spring Security 为使用用户名和密码进行身份验证提供了全面的支持。spring-doc.cadn.net.cn

您可以使用以下内容配置用户名和密码身份验证:spring-doc.cadn.net.cn

简单的用户名/密码示例
@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);
	}

}
<http>
	<intercept-url pattern="/**" access="authenticated"/>
	<form-login />
	<http-basic />

	<user-service>
		<user name="user"
			password="{noop}password"
			authorities="ROLE_USER" />
	</user-service>
</http>
import org.springframework.security.config.annotation.web.invoke

@Configuration
@EnableWebSecurity
class SecurityConfig {

	@Bean
	fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
		http {
			authorizeHttpRequests {
                authorize(anyRequest, authenticated)
			}
			formLogin { }
			httpBasic { }
        }

		return http.build()
	}

	@Bean
	fun userDetailsService(): UserDetailsService {
		val user = User.withDefaultPasswordEncoder()
			.username("user")
			.password("password")
			.roles("USER")
			.build()

		return InMemoryUserDetailsManager(user)
	}

}

前面的配置会自动注册一个内存中UserDetailsService使用SecurityFilterChain中,注册DaoAuthenticationProvider替换为默认的AuthenticationManager,并启用表单登录HTTP 基本身份验证。spring-doc.cadn.net.cn

要了解有关用户名/密码身份验证的更多信息,请考虑以下使用案例:spring-doc.cadn.net.cn

发布AuthenticationManager

一个相当常见的要求是发布AuthenticationManagerbean 允许自定义身份验证,例如在@Service或 Spring MVC@Controller. 例如,您可能希望通过 REST API 而不是使用表单登录对用户进行身份验证。spring-doc.cadn.net.cn

您可以发布这样的AuthenticationManager对于使用以下配置的自定义身份验证方案:spring-doc.cadn.net.cn

发布AuthenticationManager用于自定义身份验证的 bean
@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();
	}

}
<http>
	<intercept-url pattern="/login" access="permitAll"/>
	<intercept-url pattern="/**" access="authenticated"/>

	<bean id="authenticationManager"
			class="org.springframework.security.authentication.ProviderManager">
		<constructor-arg>
			<bean class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
				<property name="userDetailsService" ref="userDetailsService" />
				<property name="passwordEncoder" ref="passwordEncoder" />
			</bean>
		</constructor-arg>
	</bean>

	<user-service id="userDetailsService">
		<user name="user"
			password="{noop}password"
			authorities="ROLE_USER" />
	</user-service>

	<bean id="passwordEncoder"
    	    class="org.springframework.security.crypto.factory.PasswordEncoderFactories" factory-method="createDelegatingPasswordEncoder"/>
</http>
@Configuration
@EnableWebSecurity
class SecurityConfig {

	@Bean
	fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
		http {
			authorizeHttpRequests {
				authorize(anyRequest, authenticated)
			}
		}

		return http.build()
	}

	@Bean
	fun authenticationManager(
			userDetailsService: UserDetailsService,
			passwordEncoder: PasswordEncoder): AuthenticationManager {
		val authenticationProvider = DaoAuthenticationProvider()
		authenticationProvider.setUserDetailsService(userDetailsService)
		authenticationProvider.setPasswordEncoder(passwordEncoder)

		return ProviderManager(authenticationProvider)
	}

	@Bean
	fun userDetailsService(): UserDetailsService {
		val user = User.withDefaultPasswordEncoder()
			.username("user")
			.password("password")
			.roles("USER")
			.build()

		return InMemoryUserDetailsManager(user)
	}

	@Bean
	fun passwordEncoder(): PasswordEncoder {
		return PasswordEncoderFactories.createDelegatingPasswordEncoder()
	}

}

完成上述配置后,您可以创建一个@RestController,它使用AuthenticationManager如下:spring-doc.cadn.net.cn

创建一个@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) {
	}

}
@RestController
class LoginController(val authenticationManager: AuthenticationManager) {

	@PostMapping("/login")
	fun login(@RequestBody loginRequest: LoginRequest): ResponseEntity<Void> {
		val authenticationRequest =
			UsernamePasswordAuthenticationToken.unauthenticated(
				loginRequest.username, loginRequest.password)
		val authenticationResponse =
			authenticationManager.authenticate(authenticationRequest)
		// ...
	}

	data class LoginRequest(val username: String, val password: String)

}

在此示例中,您负责将经过身份验证的用户保存在SecurityContextRepository如果需要。 例如,如果使用HttpSession以保留SecurityContext在请求之间,您可以使用HttpSessionSecurityContextRepository.spring-doc.cadn.net.cn

自定义AuthenticationManager

通常, Spring Security 会构建一个AuthenticationManager内部由DaoAuthenticationProvider用于用户名/密码身份验证。 在某些情况下,可能仍需要自定义AuthenticationManager由 Spring Security 使用。 例如,您可能只需要为缓存的用户禁用凭证擦除spring-doc.cadn.net.cn

推荐的方法是简单地发布您自己的AuthenticationManagerbean,Spring Security 将使用它。 您可以发布AuthenticationManager使用以下配置:spring-doc.cadn.net.cn

发布AuthenticationManager用于 Spring Security 的 bean
@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();
	}

}
<http>
	<intercept-url pattern="/login" access="permitAll"/>
	<intercept-url pattern="/**" access="authenticated"/>
	<form-login />
	<http-basic />

	<bean id="authenticationManager"
			class="org.springframework.security.authentication.ProviderManager">
		<constructor-arg>
			<bean class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
				<property name="userDetailsService" ref="userDetailsService" />
				<property name="passwordEncoder" ref="passwordEncoder" />
			</bean>
		</constructor-arg>
	</bean>

	<user-service id="userDetailsService">
		<user name="user"
			password="{noop}password"
			authorities="ROLE_USER" />
	</user-service>

	<bean id="passwordEncoder"
    	    class="org.springframework.security.crypto.factory.PasswordEncoderFactories" factory-method="createDelegatingPasswordEncoder"/>
</http>
@Configuration
@EnableWebSecurity
public class SecurityConfig {

	@Bean
	fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
		http {
			authorizeHttpRequests {
				authorize(anyRequest, authenticated)
			}
			formLogin { }
			httpBasic { }
		}

		return http.build()
	}

	@Bean
	fun authenticationManager(
			userDetailsService: UserDetailsService,
			passwordEncoder: PasswordEncoder): AuthenticationManager {
		val authenticationProvider = DaoAuthenticationProvider()
		authenticationProvider.setUserDetailsService(userDetailsService)
		authenticationProvider.setPasswordEncoder(passwordEncoder)

		val providerManager = ProviderManager(authenticationProvider)
		providerManager.eraseCredentialsAfterAuthentication = false

		return providerManager
	}

	@Bean
	fun userDetailsService(): UserDetailsService {
		val user = User.withDefaultPasswordEncoder()
			.username("user")
			.password("password")
			.roles("USER")
			.build()

		return InMemoryUserDetailsManager(user)
	}

	@Bean
	fun passwordEncoder(): PasswordEncoder {
		return PasswordEncoderFactories.createDelegatingPasswordEncoder()
	}

}

或者,您可以利用AuthenticationManagerBuilder用于构建 Spring Security 的全局AuthenticationManager作为 Bean 发布。 您可以按如下方式配置生成器:spring-doc.cadn.net.cn

配置全局AuthenticationManagerBuilder
@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);
    }

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

}