index.adoc 14 KB

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