mirror of
				https://github.com/spring-projects/spring-security.git
				synced 2025-10-24 19:28:45 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			542 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			542 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| [[servlet-authentication-unpwd]]
 | |
| = Username/Password Authentication
 | |
| :page-section-summary-toc: 1
 | |
| :figures: images/servlet/authentication/unpwd
 | |
| :icondir: images/icons
 | |
| 
 | |
| One of the most common ways to authenticate a user is by validating a username and password.
 | |
| Spring Security provides comprehensive support for authenticating with a username and password.
 | |
| 
 | |
| You can configure username and password authentication using the following:
 | |
| 
 | |
| .Simple Username/Password Example
 | |
| [tabs]
 | |
| =====
 | |
| Java::
 | |
| +
 | |
| [source,java,role="primary"]
 | |
| ----
 | |
| @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);
 | |
| 	}
 | |
| 
 | |
| }
 | |
| ----
 | |
| 
 | |
| XML::
 | |
| +
 | |
| [source,xml,role="secondary"]
 | |
| ----
 | |
| <http>
 | |
| 	<intercept-url pattern="/**" access="authenticated"/>
 | |
| 	<form-login />
 | |
| 	<http-basic />
 | |
| 
 | |
| 	<user-service>
 | |
| 		<user name="user"
 | |
| 			password="{noop}password"
 | |
| 			authorities="ROLE_USER" />
 | |
| 	</user-service>
 | |
| </http>
 | |
| ----
 | |
| 
 | |
| Kotlin::
 | |
| +
 | |
| [source,kotlin,role="secondary"]
 | |
| ----
 | |
| 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)
 | |
| 	}
 | |
| 
 | |
| }
 | |
| ----
 | |
| =====
 | |
| 
 | |
| The preceding configuration automatically registers an xref:servlet/authentication/passwords/in-memory.adoc[in-memory `UserDetailsService`] with the `SecurityFilterChain`, registers the xref:servlet/authentication/passwords/dao-authentication-provider.adoc[`DaoAuthenticationProvider`] with the default xref:servlet/authentication/architecture.adoc#servlet-authentication-authenticationmanager[`AuthenticationManager`], and enables xref:servlet/authentication/passwords/form.adoc[Form Login] and xref:servlet/authentication/passwords/basic.adoc[HTTP Basic] authentication.
 | |
| 
 | |
| To learn more about username/password authentication, consider the following use cases:
 | |
| 
 | |
| * I want to xref:servlet/authentication/passwords/form.adoc[learn how Form Login works]
 | |
| * I want to xref:servlet/authentication/passwords/basic.adoc[learn how HTTP Basic authentication works]
 | |
| * I want to xref:servlet/authentication/passwords/dao-authentication-provider.adoc[learn how `DaoAuthenticationProvider` works]
 | |
| * I want to xref:servlet/authentication/passwords/in-memory.adoc[manage users in memory]
 | |
| * I want to xref:servlet/authentication/passwords/jdbc.adoc[manage users in a database]
 | |
| * I want to xref:servlet/authentication/passwords/ldap.adoc#servlet-authentication-ldap-authentication[manage users in LDAP]
 | |
| * I want to <<publish-authentication-manager-bean,publish an `AuthenticationManager` bean>> for custom authentication
 | |
| * I want to <<customize-global-authentication-manager,customize the global `AuthenticationManager`>>
 | |
| 
 | |
| [[publish-authentication-manager-bean]]
 | |
| == Publish an `AuthenticationManager` bean
 | |
| 
 | |
| A fairly common requirement is publishing an `AuthenticationManager` bean to allow for custom authentication, such as in a `@Service` or Spring MVC `@Controller`.
 | |
| For example, you may want to authenticate users via a REST API instead of using xref:servlet/authentication/passwords/form.adoc[Form Login].
 | |
| 
 | |
| You can publish such an `AuthenticationManager` for custom authentication scenarios using the following configuration:
 | |
| 
 | |
| .Publish `AuthenticationManager` bean for Custom Authentication
 | |
| [tabs]
 | |
| =====
 | |
| Java::
 | |
| +
 | |
| [source,java,role="primary"]
 | |
| ----
 | |
| @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();
 | |
| 	}
 | |
| 
 | |
| }
 | |
| ----
 | |
| 
 | |
| XML::
 | |
| +
 | |
| [source,xml,role="secondary"]
 | |
| ----
 | |
| <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>
 | |
| ----
 | |
| 
 | |
| Kotlin::
 | |
| +
 | |
| [source,kotlin,role="secondary"]
 | |
| ----
 | |
| import org.springframework.security.config.annotation.web.invoke
 | |
| 
 | |
| @Configuration
 | |
| @EnableWebSecurity
 | |
| class SecurityConfig {
 | |
| 
 | |
| 	@Bean
 | |
| 	fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
 | |
| 		http {
 | |
| 			authorizeHttpRequests {
 | |
| 				authorize("/login", permitAll)
 | |
| 				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()
 | |
| 	}
 | |
| 
 | |
| }
 | |
| ----
 | |
| =====
 | |
| 
 | |
| With the preceding configuration in place, you can create a `@RestController` that uses the `AuthenticationManager` as follows:
 | |
| 
 | |
| 
 | |
| .Create a `@RestController` for Authentication
 | |
| [tabs]
 | |
| =====
 | |
| Java::
 | |
| +
 | |
| [source,java,role="primary"]
 | |
| ----
 | |
| @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) {
 | |
| 	}
 | |
| 
 | |
| }
 | |
| ----
 | |
| 
 | |
| Kotlin::
 | |
| +
 | |
| [source,kotlin,role="secondary"]
 | |
| ----
 | |
| @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)
 | |
| 
 | |
| }
 | |
| ----
 | |
| =====
 | |
| 
 | |
| [NOTE]
 | |
| ====
 | |
| In this example, it is your responsibility to save the authenticated user in the `SecurityContextRepository` if needed.
 | |
| For example, if using the `HttpSession` to persist the `SecurityContext` between requests, you can use xref:servlet/authentication/persistence.adoc#httpsecuritycontextrepository[`HttpSessionSecurityContextRepository`].
 | |
| ====
 | |
| 
 | |
| [[customize-global-authentication-manager]]
 | |
| == Customize the `AuthenticationManager`
 | |
| 
 | |
| Normally, Spring Security builds an `AuthenticationManager` internally composed of a `DaoAuthenticationProvider` for username/password authentication.
 | |
| In certain cases, it may still be desired to customize the instance of `AuthenticationManager` used by Spring Security.
 | |
| For example, you may need to simply disable xref:servlet/authentication/architecture.adoc#servlet-authentication-providermanager-erasing-credentials[credential erasure] for cached users.
 | |
| 
 | |
| The recommended way to do this is to simply publish your own `AuthenticationManager` bean, and Spring Security will use it.
 | |
| You can publish an `AuthenticationManager` using the following configuration:
 | |
| 
 | |
| .Publish `AuthenticationManager` bean for Spring Security
 | |
| [tabs]
 | |
| =====
 | |
| Java::
 | |
| +
 | |
| [source,java,role="primary"]
 | |
| ----
 | |
| @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();
 | |
| 	}
 | |
| 
 | |
| }
 | |
| ----
 | |
| 
 | |
| XML::
 | |
| +
 | |
| [source,xml,role="secondary"]
 | |
| ----
 | |
| <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>
 | |
| ----
 | |
| 
 | |
| Kotlin::
 | |
| +
 | |
| [source,kotlin,role="secondary"]
 | |
| ----
 | |
| import org.springframework.security.config.annotation.web.invoke
 | |
| 
 | |
| @Configuration
 | |
| @EnableWebSecurity
 | |
| class SecurityConfig {
 | |
| 
 | |
| 	@Bean
 | |
| 	fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
 | |
| 		http {
 | |
| 			authorizeHttpRequests {
 | |
| 				authorize("/login", permitAll)
 | |
| 				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()
 | |
| 	}
 | |
| 
 | |
| }
 | |
| ----
 | |
| =====
 | |
| 
 | |
| Alternatively, you can take advantage of the fact that the `AuthenticationManagerBuilder` used to build Spring Security's global `AuthenticationManager` is published as a bean.
 | |
| You can configure the builder as follows:
 | |
| 
 | |
| .Configure global `AuthenticationManagerBuilder`
 | |
| [tabs]
 | |
| =====
 | |
| Java::
 | |
| +
 | |
| [source,java,role="primary"]
 | |
| ----
 | |
| @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);
 | |
| 	}
 | |
| 
 | |
| }
 | |
| ----
 | |
| 
 | |
| Kotlin::
 | |
| +
 | |
| [source,kotlin,role="secondary"]
 | |
| ----
 | |
| 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)
 | |
| 	}
 | |
| 
 | |
| }
 | |
| ----
 | |
| =====
 |