Authentication:认证
AuthenticationManagerBuilder:身份验证管理器生成器
encoder:编译器
PasswordEncoder:密码编译器
先来看一下假如用SpringSecurity默认的用户认证,用户名和密码是什么?
下面来看一下SecurityAutoConfiguration.class自动配置类,如下图
下面再来看一下SecurityProperties.class类,如下图:
首先配置类需要继承WebSecurityConfigurerAdapter适配器类,WebSecurityConfigurerAdapter 类是个适配器, 在配置的时候,需要我们自己写个配置类去继承他,然后编写自己所特殊需要的配置。
也可以同时把多个用户信息以及它们的权限存到内存中,只需要在多个用户信息之间用and()方法连接就行了
// 自定义配置认证规则
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("zhangsan").password("12345").roles("SuperAdmin")
.and()
.withUser("lisi").password("12345").roles("Admin")
.and()
.withUser("wangwu").password("12345").roles("Employee");
}
下面重点描述一下上图中所说的There is no PasswordEcoder mapped for the id "null"异常,以及谈谈它的解决办法:
Spring security 5.0中新增了多种加密方式,也改变了默认的密码格式.
我们来看一下官方文档:
The general format for a password is:
{id}encodedPassword
Such that id is an identifier used to look up which PasswordEncoder should be used and encodedPassword is the original encoded password for the selected PasswordEncoder. The id must be at the beginning of the password, start with { and end with }. If the id cannot be found, the id will be null. For example, the following might be a list of passwords encoded using different id. All of the original passwords are "password".
{bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG
{noop}password
{pbkdf2}5d923b44a6d129f3ddf3e3c8d29412723dcbde72445e8ef6bf3b508fbf17fa4ed4d6b99ca763d8dc
{scrypt}$e0801$8bWJaSu2IKSn9Z9kM+TPXfOc/9bdYSrN1oD9qfVThWEwdRTnO7re7Ei+fUZRJ68k9lTyuTeUp4of4g24hHnazw==$OAOec05+bXxvuu/1qZ6NUR+xQYvYv7BeL1QxwRpY5Pc=
{sha256}97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0
**这段话的意思是说,现如今Spring Security中密码的存储格式是“{id}…………”.前面的id是加密方式,id可以是bcrypt、sha256等,后面跟着的是加密后的密码.也就是说,程序拿到传过来的密码的时候,会首先查找被“{”和“}”包括起来的id,来确定后面的密码是被怎么样加密的,如果找不到就认为id是null.**这也就是为什么我们的程序会报错:There is no PasswordEncoder mapped for the id “null”.官方文档举的例子中是各种加密方式针对同一密码加密后的存储形式,原始密码都是“password”.
需要修改一下configure中的代码,我们要将前端传过来的密码进行某种方式加密,Spring Security 官方推荐的是使用bcrypt加密方式.
是这样的:
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//inMemoryAuthentication 从内存中获取
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()).withUser("user1").password(new BCryptPasswordEncoder().encode("123")).roles("USER");
}
inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())",这相当于登陆时用BCrypt加密方式对用户密码进行处理.以前的".password(“123”)" 变成了 “.password(new BCryptPasswordEncoder().encode(“123”))”,这相当于对内存中的密码进行Bcrypt编码加密.如果比对时一致,说明密码正确,才允许登陆.
总结:在用户进行用户认证登录的时候,前端传来的密码会用BCrpt加密方式进行加密,加密后的密码格式是{id}password,然后程序员会先获取到加密方式也即是{id},假设没有写passwordEncoder(new BCryptPasswordEncoder())那么前端传来的值就不会用BCrpt加密方式进行加密,所以程序员获取前端传来的值时是寻找不到密码中的{id}也即是加密方式的,因此就会报There is no PasswordEcoder mapped for the id "null"异常。passwordEncoder(new BCryptPasswordEncoder())可以理解成是告诉系统到底用什么样的加密方式对前端传来的数据进行加密。假设程序中用了passwordEncoder(new BCryptPasswordEncoder())那么获取到用bcrypt加密方式的密码后会和内存中存储的用bcrypt方式进行加密的密码进行比较,如果相同那么说明用户输入的密码和内存中的密码一致,则允许登录。
BCryptPasswordEncoder是PasswordEncoder接口的实现类
在对密码加密的时候需要调用相关的实现类如BCryptPasswordEncoder的encode方法,当用户在登录时,就会自动调用 matches 方法进行密码比对。
首先先来看一下数据库中的users表,如下图:
自定义的用户细节实现类如下图: