述
上一个案例中,我们简单的实现了用户的登录,用的是Spring Security的默认的用户名和密码, 实际情况中,我们肯定是要从数据库里面去获取用户信息,然后接下来就看一下具体的要如何实现
大致流程
登录就是用户名,密码还有一些其他的校验, 上文中对认证源码有了一些大致的了解,我们自定义登录主要就是实现从数据库里面去,回顾一下这个部分的源码:
这里调用了一个 retrieveUser(...)
这个方法, 返回的是一个UserDetails
, 这个需要我们自己去实现 UserDetailsService
, 在这个里面去查询数据库
首先,看一下 UserDetailsService
,这个类的源码, 如下:
很简单,就是一个接口,里面有一个根据用户名去获取用户信息的方法,然后我们新建一个类,实现这个接口,然后重写方法就可以,这里返回的是一个 UserDetails
对象,这里直接用了security提供的一个user对象,当然也可以自己实现,来看一下他里面的几个属性
首先是个权限的集合,然后是密码,用户名,是否非过期, 是否非锁定,凭证是否非过期,是否启用.
这下面四个boolean值,只要有一个设置为false,就不能登录
手动实现用户验证
然后再看一下我们的代码,新建类,实现 UserDetailsService
,具体代码如下:
1 | @Component |
先是根据用户名从数据库里面查询出用户信息来,然后根据自己的情况把4个Boolean值赋值,然后最后一个集合是权限,这里先随便给个值
PasswordEncoder
在Spring Security中, 验证密码是否正确, 这个事情是交给Spring Security去完成的, 我们只需要按照用户名去查询这个用户就ok了,最后查询出来的信息给到 UserDetails
里面,交给 Spring Security 去验证
我们在数据库中存储的密码都是经过加密的,所以我们还需要告诉 Spring Security 我们的加密方式 ,就是 PasswordEncoder
, 先看一下他的源码
这个也是一个接口,里面就两个方法, 一个是加密的方法,这个可以在用户注册的时候给密码加密, 然后是一个匹配的方法, 需要传入原始密码,和加密后的密码, 然后返回是否匹配, 这个东西我们是可以自己实现的,比如常用的MD5等, 这里他还提供了很多默认的实现,这里就先用他提供的 BCryptPasswordEncoder
在前面案例创建的 BrowserSecurityConfig
中,加入下面的配置
1 | @Bean |
这样密码验证器就生效了
测试
最后看一下我在 UserServiceImpl
中的代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29@Service
public class UserServiceImpl implements UserService {
private static Map<String, User> userMap = new HashMap<>(3);
/**
* 初始化数据,模拟从数据库获取数据
*/
static{
// 密码是经过加密的 都是 123456 通过 BCryptPasswordEncoder 加密
User user1 = new User(1L, "zhangsan", "$2a$10$W17jDdV96PUBlVx/PL6zDuaK3rv9uH.DKLwkFaD6lhOPkv3GD5sEu", false, true);
User user2 = new User(2L, "lisi", "$2a$10$W17jDdV96PUBlVx/PL6zDuaK3rv9uH.DKLwkFaD6lhOPkv3GD5sEu", false, true);
User user3 = new User(3L, "lockedtest", "$2a$10$W17jDdV96PUBlVx/PL6zDuaK3rv9uH.DKLwkFaD6lhOPkv3GD5sEu", true, true);
User user4 = new User(4L, "enabletest", "$2a$10$W17jDdV96PUBlVx/PL6zDuaK3rv9uH.DKLwkFaD6lhOPkv3GD5sEu", false, false);
userMap.put(user1.getName(), user1);
userMap.put(user2.getName(), user2);
userMap.put(user3.getName(), user3);
userMap.put(user4.getName(), user4);
}
@Override
public User findUserByName(String username) {
User user = userMap.get(username);
return user;
}
}
这里应该是要从数据库查询,我这里就模拟了几个用户,密码都是通过 BCryptPasswordEncoder
加密好的,加密这步应该是放到注册里面的
然后启动项目,看一下效果, 访问随便一个接口,我们上面可以试试锁定的用户,还有失效用户登录,还有密码错误的时候,返回分别如下:
然后输入正确的密码,就可以访问到接口了
总结
关于自定义认证主要做了以下两件事:
- 手动实现
UserDetailsService
, 跟数据库交互做登录验证 - 然后就是
PasswordEncoder
自定义密码加密解密的方法,然后配置到项目里面