用户提交账号密码,UsernamePasswordAuthenticationFilter过滤器会构造一个UsernamePasswordAuthenticationToken对象实现类,将用请求信息封装为Authentication,接下来到达AuthenticationManager接口(认证相关的核心接口)的一个实现类的Authentication的方法,一切认证都从AuthenticationManager开始,不同的实现类有不同的认证方式,比如账号密码,邮箱,语音,指纹等,AuthenticationManager接口的常用实现类ProviderManager 内部会维护一个List列表,存放多种认证方式,实际上这是委托者模式的应用(Delegate),DaoAuthenticationProvider:用于解析并认证 UsernamePasswordAuthenticationToken 的这样一个认证服务提供者,对应以上的几种登录方式。
UserDetailsService接口:Spring Security 会将前端填写的username 传给 UserDetailService.loadByUserName方法。我们只需要从数据库中根据用户名查找到用户信息然后封装为UserDetails的实现类返回给SpringSecurity 即可,自己不需要进行密码的比对工作,密码比对交由SpringSecurity处理。
UserDetails接口:提供核心用户信息。通过UserDetailsService根据用户名获取处理的用户信息要封装成UserDetails对象返回。然后将这些信息封装到Authentication对象中。
springsecurity已经提供了完整的流程,我们只需要在关键位置编写代码即可
登录:
- 创建一个类实现UserDetailsService接口,重写其中的方法。增加用户名从数据库中查询用户信息
- 因为UserDetailsService方法的返回值是UserDetails类型,所以需要定义一个类,实现该接口,把用户信息封装在其中。
- 我们可以定义一个SpringSecurity的配置类,SpringSecurity要求这个配置类要继承WebSecurityConfigurerAdapter。注入BCryptPasswordEncoder这个bean,是用来加密的
- 接下我们需要自定义登陆接口,然后让SpringSecurity对这个接口放行,让用户访问这个接口的时候不用登录也能访问。
- 开放登录接口,通过AuthenticationManager的authenticate方法来进行用户认证,需要在SecurityConfig中配置把AuthenticationManager注入容器
- 登录接口实现类,通过AuthenticationManager的authenticate方法来进行用户认证,需要在SecurityConfig中配置把AuthenticationManager注入容器
- 我们需要自定义一个过滤器,这个过滤器会去获取请求头中的token,对token进行解析取出其中的userid。使用userid去redis中获取对应的LoginUser对象。然后封装Authentication对象存入SecurityContextHolder,把token校验过滤器添加到过滤器链中
- 退出登录,我们只需要定义一个登陆接口,然后获取SecurityContextHolder中的认证信息,删除redis中对应的数据即可。
授权基本流程
在SpringSecurity中,会使用默认的FilterSecurityInterceptor来进行权限校验。在FilterSecurityInterceptor中会从SecurityContextHolder获取其中的Authentication,然后获取其中的权限信息。当前用户是否拥有访问当前资源所需的权限。
所以我们在项目中只需要把当前登录用户的权限信息也存入Authentication。然后设置我们的资源所需要的权限即可。