基于数据库表进行认证
用户数据通常会存储在关系型数据库中,并通过 JDBC 进行访问。为了配置 Spring Security 使用以 JDBC 为支撑的用户存储,我们可以使用 jdbcAuthentication() 方法,所需的最少配置如下所示:
@Autowired
DataSource dataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource);
}
我们必须要配置的只是一个 DataSource,这样的话,就能访问关系型数据库了。在这里,DataSource 是通过自动装配的技巧得到的。
重写默认的用户查询功能
尽管默认的最少配置能够让一切运转起来,但是它对我们的数据库模式有一些要求。下面的代码片段来源于 Spring Security 内部,这块代码展现了当查找用户信息时所执行的 SQL 查询语句:
public static final String DEF_USERS_BY_USERNAME_QUERY =
"select username, password, enabled " +
"from users " +
"where username = ?";
public static final String DEF_AUTHORITIES_BY_USERNAME_QUERY =
"select username, authority " +
"from authorities " +
"where username = ?";
public static final String DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY =
"select g.id, g.group_name, ga.authority " +
"from groups g, group_members gm, group_authorities ga " +
"where gm.username = ? " +
"and g.id = ga.group_id " +
"and g.id = gm.group_id";
在第一个查询中,我们获取了用户的用户名、密码以及是否启用的信息,这些信息会用来进行用户认证。
接下来的查询查找了用户所授予的权限,用来进行鉴权。
最后一个查询中,查找了用户作为群组的成员所授予的权限。
可以按照如下的方式配置自己的查询:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery(
"select username, password, true " +
"from Spitter where username=?")
.authoritiesByUsernameQuery(
"select username, 'ROLE_USER' from Spitter where username=?");
}
在本例中,我们只重写了认证和基本权限的查询语句,但是通过调用 groupAuthoritiesByUsername() 方法,我们也能够将群组权限重写为自定义的查询语句。
使用编码后的密码
上面的认证查询,会预期用户密码存储在了数据库之中。这里唯一的问题在于如果密码明文存储的话,会很容易受到黑客的窃取。但是,如果数据库中的密码进行了编码的话,那么认证就会失败,因为它与用户提交的明文密码并不匹配。
为了解决这个问题,我们需要借助 passwordEncoder() 方法指定一个密码编码器(encoder):
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery(
"select username, password, true " +
"from Spitter where username=?")
.authoritiesByUsernameQuery(
"select username, 'ROLE_USER' from Spitter where username=?")
.passwordEncoder(new StandardPasswordEnconder("123456"));
}
passwordEncoder() 方法可以接受 Spring Security 中 PasswordEncoder 接口的任意实现。
Last updated