# JDBC 身份验证

Spring Security 的`JdbcDaoImpl`实现了[UserDetailsService](user-details-service.html#servlet-authentication-userdetailsservice)，以提供对基于用户名/密码的身份验证的支持这是使用 JDBC 检索的。`JdbcUserDetailsManager`扩展`JdbcDaoImpl`以通过`UserDetailsManager`接口提供`UserDetails`的管理。当 Spring Security 将其配置为[接受用户名/密码](index.html#servlet-authentication-unpwd-input)以进行身份验证时，将使用基于`UserDetails`的身份验证。

在以下几节中，我们将进行讨论：

* Spring 安全性 JDBC 身份验证使用的[默认模式](#servlet-authentication-jdbc-schema)

* [建立数据源](#servlet-authentication-jdbc-datasource)

* [JDBCuserDetailsManager Bean](#servlet-authentication-jdbc-bean)

## 默认模式

Spring 安全性为基于 JDBC 的身份验证提供了默认查询。本节提供了与默认查询一起使用的相应的默认模式。你将需要调整模式，以匹配对查询和正在使用的数据库方言的任何自定义。

### 用户模式

`JdbcDaoImpl`要求表为用户加载密码、帐户状态（已启用或禁用）和权限列表（角色）。所需的默认模式可以在下面找到。

|   |默认的模式也公开为 Classpath 名为`org/springframework/security/core/userdetails/jdbc/users.ddl`的资源。|
|---|--------------------------------------------------------------------------------------------------------------------------------|

例 1。默认用户模式

```
create table users(
	username varchar_ignorecase(50) not null primary key,
	password varchar_ignorecase(500) not null,
	enabled boolean not null
);

create table authorities (
	username varchar_ignorecase(50) not null,
	authority varchar_ignorecase(50) not null,
	constraint fk_authorities_users foreign key(username) references users(username)
);
create unique index ix_auth_username on authorities (username,authority);
```

Oracle 是一个流行的数据库选择，但需要一个稍微不同的模式。你可以在下面找到用户的默认 Oracle 模式。

例 2。Oracle 数据库的默认用户模式

```
CREATE TABLE USERS (
    USERNAME NVARCHAR2(128) PRIMARY KEY,
    PASSWORD NVARCHAR2(128) NOT NULL,
    ENABLED CHAR(1) CHECK (ENABLED IN ('Y','N') ) NOT NULL
);

CREATE TABLE AUTHORITIES (
    USERNAME NVARCHAR2(128) NOT NULL,
    AUTHORITY NVARCHAR2(128) NOT NULL
);
ALTER TABLE AUTHORITIES ADD CONSTRAINT AUTHORITIES_UNIQUE UNIQUE (USERNAME, AUTHORITY);
ALTER TABLE AUTHORITIES ADD CONSTRAINT AUTHORITIES_FK1 FOREIGN KEY (USERNAME) REFERENCES USERS (USERNAME) ENABLE;
```

### 组模式

如果你的应用程序正在利用组，那么你将需要提供组模式。可以在下面找到组的默认模式。

例 3。默认组模式

```
create table groups (
	id bigint generated by default as identity(start with 0) primary key,
	group_name varchar_ignorecase(50) not null
);

create table group_authorities (
	group_id bigint not null,
	authority varchar(50) not null,
	constraint fk_group_authorities_group foreign key(group_id) references groups(id)
);

create table group_members (
	id bigint generated by default as identity(start with 0) primary key,
	username varchar(50) not null,
	group_id bigint not null,
	constraint fk_group_members_group foreign key(group_id) references groups(id)
);
```

## 建立数据源

在配置`JdbcUserDetailsManager`之前，必须创建`DataSource`。在我们的示例中，我们将设置一个[嵌入式数据源](https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/data-access.html#jdbc-embedded-database-support)，它是用[默认用户模式](#servlet-authentication-jdbc-schema)初始化的。

例 4。嵌入式数据源

爪哇

```
@Bean
DataSource dataSource() {
	return new EmbeddedDatabaseBuilder()
		.setType(H2)
		.addScript("classpath:org/springframework/security/core/userdetails/jdbc/users.ddl")
		.build();
}
```

XML

```
<jdbc:embedded-database>
	<jdbc:script location="classpath:org/springframework/security/core/userdetails/jdbc/users.ddl"/>
</jdbc:embedded-database>
```

Kotlin

```
@Bean
fun dataSource(): DataSource {
    return EmbeddedDatabaseBuilder()
        .setType(H2)
        .addScript("classpath:org/springframework/security/core/userdetails/jdbc/users.ddl")
        .build()
}
```

在生产环境中，你将需要确保设置到外部数据库的连接。

## JdbcUserDetailsManager Bean

在这个示例中，我们使用[Spring Boot CLI](../../../features/authentication/password-storage.html#authentication-password-storage-boot-cli)对`password`的密码进行编码，并获得`{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW`的编码密码。有关如何存储密码的更多详细信息，请参见[PasswordEncoder](../../../features/authentication/password-storage.html#authentication-password-storage)小节。

例 5。JDBCuserDetailsManager

爪哇

```
@Bean
UserDetailsManager users(DataSource dataSource) {
	UserDetails user = User.builder()
		.username("user")
		.password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
		.roles("USER")
		.build();
	UserDetails admin = User.builder()
		.username("admin")
		.password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
		.roles("USER", "ADMIN")
		.build();
	JdbcUserDetailsManager users = new JdbcUserDetailsManager(dataSource);
	users.createUser(user);
	users.createUser(admin);
	return users;
}
```

XML

```
<jdbc-user-service>
	<user name="user"
		password="{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW"
		authorities="ROLE_USER" />
	<user name="admin"
		password="{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW"
		authorities="ROLE_USER,ROLE_ADMIN" />
</jdbc-user-service>
```

Kotlin

```
@Bean
fun users(dataSource: DataSource): UserDetailsManager {
    val user = User.builder()
            .username("user")
            .password("{bcrypt}$2a$10\$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
            .roles("USER")
            .build();
    val admin = User.builder()
            .username("admin")
            .password("{bcrypt}$2a$10\$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
            .roles("USER", "ADMIN")
            .build();
    val users = JdbcUserDetailsManager(dataSource)
    users.createUser(user)
    users.createUser(admin)
    return users
}
```

[In Memory](in-memory.html)[用户详细信息](user-details.html)

