登陆校验流程图
SpringSecurity流程
SpringSecurity的原理其实就是一个过滤器链,内部包含了提供各种功能的过滤器。这里我们可以看看几个重要的过滤器,图中只展示了核心过滤器,其它的非核心过滤器并没有在图中展示。
- UsernamePasswordAuthenticationFilter:负责处理我们在登陆页面填写了用户名密码后的登陆请求。默认入门案例的认证工作主要由它负责。
- ExceptionTranslationFilter:处理过滤器链中抛出的任何AccessDeniedException和AuthenticationException 。
- FilterSecurityInterceptor:负责权限校验的过滤器。
我们可以通过Debug查看当前系统中SpringSecurity过滤器链中有哪些过滤器及它们的顺序。,一共有15个过滤器
认证流程图
- Authentication接口: 它的实现类,表示当前访问系统的用户,封装了用户相关信息。
- AuthenticationManager接口:定义了认证Authentication的方法
- UserDetailsService接口:加载用户特定数据的核心接口。里面定义了一个根据用户名查询用户信息的方法。(我们可以自己实现这个接口,用自己的认证用户方式)
- UserDetails接口:提供核心用户信息。通过UserDetailsService根据用户名获取处理的用户信息要封装成UserDetails对象返回。然后将这些信息封装到Authentication对象中。
自定义思路认证的思路
前端发送账号密码到我们自己写的一个接口,然后这个接口内部去调用ProviderManager,DaoAuthenticationProvider,然后再调用我们自己实现的UserDetailService接口的自定义认证用户的方法,去数据库或者缓存中查询出用户信息后,封装成UserDetails对象,然后验证密码,如果最后认证通过了。就用用户id或者什么东西,生成一个jwt token令牌,把这个令牌返回给前端。
下次前端登陆时就带上这token在请求头里面,进行访问,自己可以写一个jwt认证过滤器,来获取请求头里面的token,解析token,然后拿到用户id,用这个用户id去redis里面查询,就能获取到用户的详细信息了,把用户详细信息放入SecurityContextHolder里面,其他的过滤器也能拿到这些数据。关于密码加密存储
SpringSecurity自定义认证授权
如果只做了上面自定义的第4,5步,第2步没有配置加密。
运行项目,如果输入数据库里面的账号密码登陆,可能会出现这种情况。
明明账号密码和数据库一样的啊?那是因为数据库是明文密码,如果要使用明文密码,需要在数据库存储的密码前面加上{noop}
标记,然后登陆正常输入密码就行了
实际项目中我们不会把密码明文存储在数据库中。
默认使用的PasswordEncoder
要求数据库中的密码格式为:{id}password
。它会根据id去判断密码的加密方式。但是我们一般不会采用这种方式。所以就需要替换PasswordEncoder
。
我们一般使用SpringSecurity
为我们提供的BCryptPasswordEncoder
。
我们只需要使用把BCryptPasswordEncoder
对象注入Spring容器中,SpringSecurity
就会使用该PasswordEncoder
来进行密码校验。
看自定义认证授权的第二步。
也可以直接测试一下
@Test
void T(){
BCryptPasswordEncoder bpwe = new BCryptPasswordEncoder();
//PasswordEncoder接口的方法
//明文加密成密文
String encode = bpwe.encode("123456");
String encode2 = bpwe.encode("123456");
System.out.println(encode);
System.out.println(encode2);
//明文密文是否匹配
boolean ismatch = bpwe.matches("123456", encode);
System.out.println(ismatch);
}
虽然两次明文一样,但是加密后的结果却不一样,使用了加盐算法。
把这个明文加密后的结果存入数据库,然后在认证的时候输入明文密码,SpringSercurity会自动把我们输入的明文密码和密文进行匹配。