index.adoc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. [[servlet-authentication-unpwd]]
  2. = Username/Password Authentication
  3. :page-section-summary-toc: 1
  4. :figures: images/servlet/authentication/unpwd
  5. :icondir: images/icons
  6. One of the most common ways to authenticate a user is by validating a username and password.
  7. Spring Security provides comprehensive support for authenticating with a username and password.
  8. You can configure username and password authentication using the following:
  9. .Simple Username/Password Example
  10. [tabs]
  11. =====
  12. Java::
  13. +
  14. [source,java,role="primary"]
  15. ----
  16. @Configuration
  17. @EnableWebSecurity
  18. public class SecurityConfig {
  19. @Bean
  20. public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  21. http
  22. .authorizeHttpRequests((authorize) -> authorize
  23. .anyRequest().authenticated()
  24. )
  25. .httpBasic(Customizer.withDefaults())
  26. .formLogin(Customizer.withDefaults());
  27. return http.build();
  28. }
  29. @Bean
  30. public UserDetailsService userDetailsService() {
  31. UserDetails userDetails = User.withDefaultPasswordEncoder()
  32. .username("user")
  33. .password("password")
  34. .roles("USER")
  35. .build();
  36. return new InMemoryUserDetailsManager(userDetails);
  37. }
  38. }
  39. ----
  40. XML::
  41. +
  42. [source,xml,role="secondary"]
  43. ----
  44. <http>
  45. <intercept-url pattern="/**" access="authenticated"/>
  46. <form-login />
  47. <http-basic />
  48. <user-service>
  49. <user name="user"
  50. password="{noop}password"
  51. authorities="ROLE_USER" />
  52. </user-service>
  53. </http>
  54. ----
  55. Kotlin::
  56. +
  57. [source,kotlin,role="secondary"]
  58. ----
  59. import org.springframework.security.config.annotation.web.invoke
  60. @Configuration
  61. @EnableWebSecurity
  62. class SecurityConfig {
  63. @Bean
  64. fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
  65. http {
  66. authorizeHttpRequests {
  67. authorize(anyRequest, authenticated)
  68. }
  69. formLogin { }
  70. httpBasic { }
  71. }
  72. return http.build()
  73. }
  74. @Bean
  75. fun userDetailsService(): UserDetailsService {
  76. val user = User.withDefaultPasswordEncoder()
  77. .username("user")
  78. .password("password")
  79. .roles("USER")
  80. .build()
  81. return InMemoryUserDetailsManager(user)
  82. }
  83. }
  84. ----
  85. =====
  86. 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.
  87. To learn more about username/password authentication, consider the following use cases:
  88. * I want to xref:servlet/authentication/passwords/form.adoc[learn how Form Login works]
  89. * I want to xref:servlet/authentication/passwords/basic.adoc[learn how HTTP Basic authentication works]
  90. * I want to xref:servlet/authentication/passwords/dao-authentication-provider.adoc[learn how `DaoAuthenticationProvider` works]
  91. * I want to xref:servlet/authentication/passwords/in-memory.adoc[manage users in memory]
  92. * I want to xref:servlet/authentication/passwords/jdbc.adoc[manage users in a database]
  93. * I want to xref:servlet/authentication/passwords/ldap.adoc#servlet-authentication-ldap-authentication[manage users in LDAP]
  94. * I want to <<publish-authentication-manager-bean,publish an `AuthenticationManager` bean>> for custom authentication
  95. * I want to <<customize-global-authentication-manager,customize the global `AuthenticationManager`>>
  96. [[publish-authentication-manager-bean]]
  97. == Publish an `AuthenticationManager` bean
  98. A fairly common requirement is publishing an `AuthenticationManager` bean to allow for custom authentication, such as in a `@Service` or Spring MVC `@Controller`.
  99. For example, you may want to authenticate users via a REST API instead of using xref:servlet/authentication/passwords/form.adoc[Form Login].
  100. You can publish such an `AuthenticationManager` for custom authentication scenarios using the following configuration:
  101. .Publish `AuthenticationManager` bean for Custom Authentication
  102. [tabs]
  103. =====
  104. Java::
  105. +
  106. [source,java,role="primary"]
  107. ----
  108. @Configuration
  109. @EnableWebSecurity
  110. public class SecurityConfig {
  111. @Bean
  112. public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  113. http
  114. .authorizeHttpRequests((authorize) -> authorize
  115. .requestMatchers("/login").permitAll()
  116. .anyRequest().authenticated()
  117. );
  118. return http.build();
  119. }
  120. @Bean
  121. public AuthenticationManager authenticationManager(
  122. UserDetailsService userDetailsService,
  123. PasswordEncoder passwordEncoder) {
  124. DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider(userDetailsService);
  125. authenticationProvider.setPasswordEncoder(passwordEncoder);
  126. return new ProviderManager(authenticationProvider);
  127. }
  128. @Bean
  129. public UserDetailsService userDetailsService() {
  130. UserDetails userDetails = User.withDefaultPasswordEncoder()
  131. .username("user")
  132. .password("password")
  133. .roles("USER")
  134. .build();
  135. return new InMemoryUserDetailsManager(userDetails);
  136. }
  137. @Bean
  138. public PasswordEncoder passwordEncoder() {
  139. return PasswordEncoderFactories.createDelegatingPasswordEncoder();
  140. }
  141. }
  142. ----
  143. XML::
  144. +
  145. [source,xml,role="secondary"]
  146. ----
  147. <http>
  148. <intercept-url pattern="/login" access="permitAll"/>
  149. <intercept-url pattern="/**" access="authenticated"/>
  150. <bean id="authenticationManager"
  151. class="org.springframework.security.authentication.ProviderManager">
  152. <constructor-arg>
  153. <bean class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
  154. <constructor-arg name="userDetailsService" ref="userDetailsService" />
  155. <property name="passwordEncoder" ref="passwordEncoder" />
  156. </bean>
  157. </constructor-arg>
  158. </bean>
  159. <user-service id="userDetailsService">
  160. <user name="user"
  161. password="{noop}password"
  162. authorities="ROLE_USER" />
  163. </user-service>
  164. <bean id="passwordEncoder"
  165. class="org.springframework.security.crypto.factory.PasswordEncoderFactories" factory-method="createDelegatingPasswordEncoder"/>
  166. </http>
  167. ----
  168. Kotlin::
  169. +
  170. [source,kotlin,role="secondary"]
  171. ----
  172. import org.springframework.security.config.annotation.web.invoke
  173. @Configuration
  174. @EnableWebSecurity
  175. class SecurityConfig {
  176. @Bean
  177. fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
  178. http {
  179. authorizeHttpRequests {
  180. authorize("/login", permitAll)
  181. authorize(anyRequest, authenticated)
  182. }
  183. }
  184. return http.build()
  185. }
  186. @Bean
  187. fun authenticationManager(
  188. userDetailsService: UserDetailsService,
  189. passwordEncoder: PasswordEncoder): AuthenticationManager {
  190. val authenticationProvider = DaoAuthenticationProvider(userDetailsService)
  191. authenticationProvider.setPasswordEncoder(passwordEncoder)
  192. return ProviderManager(authenticationProvider)
  193. }
  194. @Bean
  195. fun userDetailsService(): UserDetailsService {
  196. val user = User.withDefaultPasswordEncoder()
  197. .username("user")
  198. .password("password")
  199. .roles("USER")
  200. .build()
  201. return InMemoryUserDetailsManager(user)
  202. }
  203. @Bean
  204. fun passwordEncoder(): PasswordEncoder {
  205. return PasswordEncoderFactories.createDelegatingPasswordEncoder()
  206. }
  207. }
  208. ----
  209. =====
  210. With the preceding configuration in place, you can create a `@RestController` that uses the `AuthenticationManager` as follows:
  211. .Create a `@RestController` for Authentication
  212. [tabs]
  213. =====
  214. Java::
  215. +
  216. [source,java,role="primary"]
  217. ----
  218. @RestController
  219. public class LoginController {
  220. private final AuthenticationManager authenticationManager;
  221. public LoginController(AuthenticationManager authenticationManager) {
  222. this.authenticationManager = authenticationManager;
  223. }
  224. @PostMapping("/login")
  225. public ResponseEntity<Void> login(@RequestBody LoginRequest loginRequest) {
  226. Authentication authenticationRequest =
  227. UsernamePasswordAuthenticationToken.unauthenticated(loginRequest.username(), loginRequest.password());
  228. Authentication authenticationResponse =
  229. this.authenticationManager.authenticate(authenticationRequest);
  230. // ...
  231. }
  232. public record LoginRequest(String username, String password) {
  233. }
  234. }
  235. ----
  236. Kotlin::
  237. +
  238. [source,kotlin,role="secondary"]
  239. ----
  240. @RestController
  241. class LoginController(val authenticationManager: AuthenticationManager) {
  242. @PostMapping("/login")
  243. fun login(@RequestBody loginRequest: LoginRequest): ResponseEntity<Void> {
  244. val authenticationRequest =
  245. UsernamePasswordAuthenticationToken.unauthenticated(
  246. loginRequest.username, loginRequest.password)
  247. val authenticationResponse =
  248. authenticationManager.authenticate(authenticationRequest)
  249. // ...
  250. }
  251. data class LoginRequest(val username: String, val password: String)
  252. }
  253. ----
  254. =====
  255. [NOTE]
  256. ====
  257. In this example, it is your responsibility to save the authenticated user in the `SecurityContextRepository` if needed.
  258. For example, if using the `HttpSession` to persist the `SecurityContext` between requests, you can use xref:servlet/authentication/persistence.adoc#httpsecuritycontextrepository[`HttpSessionSecurityContextRepository`].
  259. ====
  260. [[customize-global-authentication-manager]]
  261. == Customize the `AuthenticationManager`
  262. Normally, Spring Security builds an `AuthenticationManager` internally composed of a `DaoAuthenticationProvider` for username/password authentication.
  263. In certain cases, it may still be desired to customize the instance of `AuthenticationManager` used by Spring Security.
  264. For example, you may need to simply disable xref:servlet/authentication/architecture.adoc#servlet-authentication-providermanager-erasing-credentials[credential erasure] for cached users.
  265. 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.
  266. You can configure the builder as follows:
  267. .Configure global `AuthenticationManagerBuilder`
  268. [tabs]
  269. =====
  270. Java::
  271. +
  272. [source,java,role="primary"]
  273. ----
  274. @Configuration
  275. @EnableWebSecurity
  276. public class SecurityConfig {
  277. @Bean
  278. public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  279. // ...
  280. return http.build();
  281. }
  282. @Bean
  283. public UserDetailsService userDetailsService() {
  284. // Return a UserDetailsService that caches users
  285. // ...
  286. }
  287. @Autowired
  288. public void configure(AuthenticationManagerBuilder builder) {
  289. builder.eraseCredentials(false);
  290. }
  291. }
  292. ----
  293. Kotlin::
  294. +
  295. [source,kotlin,role="secondary"]
  296. ----
  297. import org.springframework.security.config.annotation.web.invoke
  298. @Configuration
  299. @EnableWebSecurity
  300. class SecurityConfig {
  301. @Bean
  302. fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
  303. // ...
  304. return http.build()
  305. }
  306. @Bean
  307. fun userDetailsService(): UserDetailsService {
  308. // Return a UserDetailsService that caches users
  309. // ...
  310. }
  311. @Autowired
  312. fun configure(builder: AuthenticationManagerBuilder) {
  313. builder.eraseCredentials(false)
  314. }
  315. }
  316. ----
  317. =====
  318. Alternatively, you may configure a local `AuthenticationManager` to override the global one.
  319. .Configure local `AuthenticationManager` for Spring Security
  320. [tabs]
  321. =====
  322. Java::
  323. +
  324. [source,java,role="primary"]
  325. ----
  326. @Configuration
  327. @EnableWebSecurity
  328. public class SecurityConfig {
  329. @Bean
  330. public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  331. http
  332. .authorizeHttpRequests((authorize) -> authorize
  333. .anyRequest().authenticated()
  334. )
  335. .httpBasic(Customizer.withDefaults())
  336. .formLogin(Customizer.withDefaults())
  337. .authenticationManager(authenticationManager());
  338. return http.build();
  339. }
  340. private AuthenticationManager authenticationManager() {
  341. DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider(userDetailsService());
  342. authenticationProvider.setPasswordEncoder(passwordEncoder());
  343. ProviderManager providerManager = new ProviderManager(authenticationProvider);
  344. providerManager.setEraseCredentialsAfterAuthentication(false);
  345. return providerManager;
  346. }
  347. private UserDetailsService userDetailsService() {
  348. UserDetails userDetails = User.withDefaultPasswordEncoder()
  349. .username("user")
  350. .password("password")
  351. .roles("USER")
  352. .build();
  353. return new InMemoryUserDetailsManager(userDetails);
  354. }
  355. private PasswordEncoder passwordEncoder() {
  356. return PasswordEncoderFactories.createDelegatingPasswordEncoder();
  357. }
  358. }
  359. ----
  360. XML::
  361. +
  362. [source,xml,role="secondary"]
  363. ----
  364. <http authentication-manager-ref="authenticationManager">
  365. <intercept-url pattern="/**" access="authenticated"/>
  366. <form-login />
  367. <http-basic />
  368. <bean id="authenticationManager"
  369. class="org.springframework.security.authentication.ProviderManager">
  370. <constructor-arg>
  371. <bean class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
  372. <constructor-arg name="userDetailsService" ref="userDetailsService" />
  373. <property name="passwordEncoder" ref="passwordEncoder" />
  374. </bean>
  375. </constructor-arg>
  376. </bean>
  377. <user-service id="userDetailsService">
  378. <user name="user"
  379. password="{noop}password"
  380. authorities="ROLE_USER" />
  381. </user-service>
  382. <bean id="passwordEncoder"
  383. class="org.springframework.security.crypto.factory.PasswordEncoderFactories" factory-method="createDelegatingPasswordEncoder"/>
  384. </http>
  385. ----
  386. Kotlin::
  387. +
  388. [source,kotlin,role="secondary"]
  389. ----
  390. import org.springframework.security.config.annotation.web.invoke
  391. @Configuration
  392. @EnableWebSecurity
  393. class SecurityConfig {
  394. @Bean
  395. fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
  396. http {
  397. authorizeHttpRequests {
  398. authorize(anyRequest, authenticated)
  399. }
  400. formLogin { }
  401. httpBasic { }
  402. authenticationManager = authenticationManager()
  403. }
  404. return http.build()
  405. }
  406. @Bean
  407. fun authenticationManager(): AuthenticationManager {
  408. val authenticationProvider = DaoAuthenticationProvider(userDetailsService())
  409. authenticationProvider.setPasswordEncoder(passwordEncoder())
  410. val providerManager = ProviderManager(authenticationProvider)
  411. providerManager.eraseCredentialsAfterAuthentication = false
  412. return providerManager
  413. }
  414. private fun userDetailsService(): UserDetailsService {
  415. val user = User.withDefaultPasswordEncoder()
  416. .username("user")
  417. .password("password")
  418. .roles("USER")
  419. .build()
  420. return InMemoryUserDetailsManager(user)
  421. }
  422. private fun passwordEncoder(): PasswordEncoder {
  423. return PasswordEncoderFactories.createDelegatingPasswordEncoder()
  424. }
  425. }
  426. ----
  427. =====