123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527 |
- [[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(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">
- <constructor-arg 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(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.
- To do this, 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)
- }
- }
- ----
- =====
- Alternatively, you may configure a local `AuthenticationManager` to override the global one.
- .Configure local `AuthenticationManager` 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
- .anyRequest().authenticated()
- )
- .httpBasic(Customizer.withDefaults())
- .formLogin(Customizer.withDefaults())
- .authenticationManager(authenticationManager());
- return http.build();
- }
- private AuthenticationManager authenticationManager() {
- DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider(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();
- }
- }
- ----
- XML::
- +
- [source,xml,role="secondary"]
- ----
- <http authentication-manager-ref="authenticationManager">
- <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">
- <constructor-arg 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(anyRequest, authenticated)
- }
- formLogin { }
- httpBasic { }
- authenticationManager = authenticationManager()
- }
- return http.build()
- }
- @Bean
- fun authenticationManager(): AuthenticationManager {
- val authenticationProvider = DaoAuthenticationProvider(userDetailsService())
- authenticationProvider.setPasswordEncoder(passwordEncoder())
- val providerManager = ProviderManager(authenticationProvider)
- providerManager.eraseCredentialsAfterAuthentication = false
- return providerManager
- }
- private fun userDetailsService(): UserDetailsService {
- val user = User.withDefaultPasswordEncoder()
- .username("user")
- .password("password")
- .roles("USER")
- .build()
- return InMemoryUserDetailsManager(user)
- }
- private fun passwordEncoder(): PasswordEncoder {
- return PasswordEncoderFactories.createDelegatingPasswordEncoder()
- }
- }
- ----
- =====
|