正文
为了让Spring 满足我们应用的需求,还需要在添加一些配置。
-
配置用户储存
-
指定哪些请求需要认证,那些请求不需要认证,以及所需要的权限
-
提供一个自定义的登录页面,替代原来简单的默认登录页。
除了Spring Security的这些功能,我们可能还希望给予安全限制,有选择性在Web视图上显示特定的内容。
4 选择查询用户详细信息的服务。
我们所需要的是用户的存储,也就是用户名、密码以及其他信息存储的地方,在进行认证决策的时候,对其进行检索。
好消息是Spring Security非常灵活,能够给予各种数据库存储来认证用户名,它内置了多种常见的用户存储场景,如内存、关系型数据库,以及LDAP,但我们也可以编写并插入自定义的用户存储实现。
借助于Spring Security的Java配置,我们能够很容易的配置一个或多个数据库存储方案。
5、使用基于内存的用户存储
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER","ADMIN");
}
通过简单那的调用
inMemoryAuthentication
就能启用内存用户村苏。但是,我们还需要一些用户,否则的话这个没用户并没有且别。需要调用weithuser为其存储添加新的用户。以及给定用户授予一个或多个角色权限的reles()方法
对于调式和开发人员来讲,基于内存的用户存储是很有用的,但对于生产级别应用来讲,这就不是最理想的状态了。
5、基于数据库进行认证
用户数据通常会存储在关系型数据库中,并通过JDBC进行访问。为了配置Spring Security使用以JDBC为支撑的用户存储,我们可以使用jdbcAuthentication()方法,所需的最少配置。
@Autowired
DataSource dataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource);
}
我们必须要配置的知识一个DataSource,这样的话就能 访问关系型数据库里。
尽管默认的最少配置能够让一切运转起来,但是,它对我们的数据库模式有一些要求。它预期存在某些存储用户数据的表。
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()
方法,我们也能够将群组权限重写为自定义的查询语句。
为了解决密码明文的问题,我们借助于passwordEncode()方法指定一个密码转码器(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 StandardPasswordEncoder("53cd3t"));
}
passwordEncoder()方法可以接受Spring Security中passwordEncoder接口的任意实现。加密模块包含了三个这样的实现
-
StandardPasswordEncoder
-
NoOpPasswordEncoder
-
BCryptPasswordEncoder
上述代码使用了
StandardPasswordEncoder
,但是如果内置的实现无法满足需求时,你可以提供自定义的实现 ,
passwordEncoder
接口如下:
package org.springframework.security.crypto.password;
public interface PasswordEncoder {
String encode(CharSequence rawPassword);
boolean matches(CharSequence rawPassword, String encodedPassword);
}
不管使用哪一个密码转化器,都需要理解的一点是:数据库的秘密是永远不会解码的,所采取的策略与之相反。用户在登录时输入的密码会按照相同的算法进行转码,然后在于数据库中已经转码过的密码进行对比,这个对比是在
PasswordEncoder
的matches()方法中进行的。