jdbc.adoc 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. [[servlet-authentication-jdbc]]
  2. = JDBC Authentication
  3. Spring Security's `JdbcDaoImpl` implements xref:servlet/authentication/passwords/user-details-service.adoc#servlet-authentication-userdetailsservice[`UserDetailsService`] to provide support for username-and-password-based authentication that is retrieved by using JDBC.
  4. `JdbcUserDetailsManager` extends `JdbcDaoImpl` to provide management of `UserDetails` through the `UserDetailsManager` interface.
  5. `UserDetails`-based authentication is used by Spring Security when it is configured to xref:servlet/authentication/passwords/index.adoc#servlet-authentication-unpwd-input[accept a username/password] for authentication.
  6. In the following sections, we discuss:
  7. * The <<servlet-authentication-jdbc-schema>> used by Spring Security JDBC Authentication
  8. * <<servlet-authentication-jdbc-datasource>>
  9. * <<servlet-authentication-jdbc-bean>>
  10. [[servlet-authentication-jdbc-schema]]
  11. == Default Schema
  12. Spring Security provides default queries for JDBC-based authentication.
  13. This section provides the corresponding default schemas used with the default queries.
  14. You need to adjust the schema to match any customizations to the queries and the database dialect you use.
  15. [[servlet-authentication-jdbc-schema-user]]
  16. === User Schema
  17. `JdbcDaoImpl` requires tables to load the password, account status (enabled or disabled) and a list of authorities (roles) for the user.
  18. [NOTE]
  19. ====
  20. The default schema is also exposed as a classpath resource named `org/springframework/security/core/userdetails/jdbc/users.ddl`.
  21. ====
  22. .Default User Schema
  23. [source,sql]
  24. ----
  25. create table users(
  26. username varchar_ignorecase(50) not null primary key,
  27. password varchar_ignorecase(500) not null,
  28. enabled boolean not null
  29. );
  30. create table authorities (
  31. username varchar_ignorecase(50) not null,
  32. authority varchar_ignorecase(50) not null,
  33. constraint fk_authorities_users foreign key(username) references users(username)
  34. );
  35. create unique index ix_auth_username on authorities (username,authority);
  36. ----
  37. Oracle is a popular database choice but requires a slightly different schema:
  38. .Default User Schema for Oracle Databases
  39. [source,sql]
  40. ----
  41. CREATE TABLE USERS (
  42. USERNAME NVARCHAR2(128) PRIMARY KEY,
  43. PASSWORD NVARCHAR2(128) NOT NULL,
  44. ENABLED CHAR(1) CHECK (ENABLED IN ('Y','N') ) NOT NULL
  45. );
  46. CREATE TABLE AUTHORITIES (
  47. USERNAME NVARCHAR2(128) NOT NULL,
  48. AUTHORITY NVARCHAR2(128) NOT NULL
  49. );
  50. ALTER TABLE AUTHORITIES ADD CONSTRAINT AUTHORITIES_UNIQUE UNIQUE (USERNAME, AUTHORITY);
  51. ALTER TABLE AUTHORITIES ADD CONSTRAINT AUTHORITIES_FK1 FOREIGN KEY (USERNAME) REFERENCES USERS (USERNAME) ENABLE;
  52. ----
  53. [[servlet-authentication-jdbc-schema-group]]
  54. === Group Schema
  55. If your application uses groups, you need to provide the groups schema:
  56. .Default Group Schema
  57. [source,sql]
  58. ----
  59. create table groups (
  60. id bigint generated by default as identity(start with 0) primary key,
  61. group_name varchar_ignorecase(50) not null
  62. );
  63. create table group_authorities (
  64. group_id bigint not null,
  65. authority varchar(50) not null,
  66. constraint fk_group_authorities_group foreign key(group_id) references groups(id)
  67. );
  68. create table group_members (
  69. id bigint generated by default as identity(start with 0) primary key,
  70. username varchar(50) not null,
  71. group_id bigint not null,
  72. constraint fk_group_members_group foreign key(group_id) references groups(id)
  73. );
  74. ----
  75. [[servlet-authentication-jdbc-datasource]]
  76. == Setting up a DataSource
  77. Before we configure `JdbcUserDetailsManager`, we must create a `DataSource`.
  78. In our example, we set up an https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/data-access.html#jdbc-embedded-database-support[embedded DataSource] that is initialized with the <<servlet-authentication-jdbc-schema,default user schema>>.
  79. .Embedded Data Source
  80. [tabs]
  81. ======
  82. Java::
  83. +
  84. [source,java,role="primary"]
  85. ----
  86. @Bean
  87. DataSource dataSource() {
  88. return new EmbeddedDatabaseBuilder()
  89. .setType(H2)
  90. .addScript(JdbcDaoImpl.DEFAULT_USER_SCHEMA_DDL_LOCATION)
  91. .build();
  92. }
  93. ----
  94. XML::
  95. +
  96. [source,xml,role="secondary"]
  97. ----
  98. <jdbc:embedded-database>
  99. <jdbc:script location="classpath:org/springframework/security/core/userdetails/jdbc/users.ddl"/>
  100. </jdbc:embedded-database>
  101. ----
  102. Kotlin::
  103. +
  104. [source,kotlin,role="secondary"]
  105. ----
  106. @Bean
  107. fun dataSource(): DataSource {
  108. return EmbeddedDatabaseBuilder()
  109. .setType(H2)
  110. .addScript(JdbcDaoImpl.DEFAULT_USER_SCHEMA_DDL_LOCATION)
  111. .build()
  112. }
  113. ----
  114. ======
  115. In a production environment, you want to ensure that you set up a connection to an external database.
  116. [[servlet-authentication-jdbc-bean]]
  117. == JdbcUserDetailsManager Bean
  118. In this sample, we use xref:features/authentication/password-storage.adoc#authentication-password-storage-boot-cli[Spring Boot CLI] to encode a password value of `password` and get the encoded password of `+{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW+`.
  119. See the xref:features/authentication/password-storage.adoc#authentication-password-storage[PasswordEncoder] section for more details about how to store passwords.
  120. .JdbcUserDetailsManager
  121. [tabs]
  122. ======
  123. Java::
  124. +
  125. [source,java,role="primary",attrs="-attributes"]
  126. ----
  127. @Bean
  128. UserDetailsManager users(DataSource dataSource) {
  129. UserDetails user = User.builder()
  130. .username("user")
  131. .password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
  132. .roles("USER")
  133. .build();
  134. UserDetails admin = User.builder()
  135. .username("admin")
  136. .password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
  137. .roles("USER", "ADMIN")
  138. .build();
  139. JdbcUserDetailsManager users = new JdbcUserDetailsManager(dataSource);
  140. users.createUser(user);
  141. users.createUser(admin);
  142. return users;
  143. }
  144. ----
  145. XML::
  146. +
  147. [source,xml,role="secondary",attrs="-attributes"]
  148. ----
  149. <jdbc-user-service>
  150. <user name="user"
  151. password="{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW"
  152. authorities="ROLE_USER" />
  153. <user name="admin"
  154. password="{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW"
  155. authorities="ROLE_USER,ROLE_ADMIN" />
  156. </jdbc-user-service>
  157. ----
  158. Kotlin::
  159. +
  160. [source,kotlin,role="secondary",attrs="-attributes"]
  161. ----
  162. @Bean
  163. fun users(dataSource: DataSource): UserDetailsManager {
  164. val user = User.builder()
  165. .username("user")
  166. .password("{bcrypt}$2a$10\$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
  167. .roles("USER")
  168. .build();
  169. val admin = User.builder()
  170. .username("admin")
  171. .password("{bcrypt}$2a$10\$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
  172. .roles("USER", "ADMIN")
  173. .build();
  174. val users = JdbcUserDetailsManager(dataSource)
  175. users.createUser(user)
  176. users.createUser(admin)
  177. return users
  178. }
  179. ----
  180. ======