springsecurity认证流程和核心组件
用户认证
用户认证流程:
1、用户认证核心组件
**我们系统中会有许多用户,确认当前是哪个用户正在使用我们系统就是登录认证的最终目的。这里我们就提取出了一个核心概念:**当前登录用户/当前认证用户。整个系统安全都是围绕当前登录用户展开的,这个不难理解,要是当前登录用户都不能确认了,那A下了一个订单,下到了B的账户上这不就乱套了。这一概念在Spring Security中的体现就是 Authentication
,它存储了认证信息,代表当前登录用户。
我们在程序中如何获取并使用它呢?我们需要通过 **SecurityContext
来获取 Authentication
,SecurityContext
就是我们的上下文对象!这个上下文对象则是交由 SecurityContextHolder
进行管理,你可以在程序任何地方**使用它:
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
SecurityContextHolder
原理非常简单,就是使用 ThreadLocal
来保证一个线程中传递同一个对象!
现在我们已经知道了Spring Security中三个核心组件:
** **1、Authentication
:存储了认证信息,代表当前登录用户
** **2、SeucirtyContext
:上下文对象,用来获取 Authentication
** **3、SecurityContextHolder
:上下文管理对象,用来在程序任何地方获取 SecurityContext
Authentication
中是什么信息呢:
** **1、Principal
:用户信息,没有认证时一般是用户名,认证后一般是用户对象
** **2、Credentials
:用户凭证,一般是密码
** **3、Authorities
:用户权限
2、用户认证
Spring Security是怎么进行用户认证的呢?
AuthenticationManager
就是Spring Security用于执行身份验证的组件,只需要调用它的 authenticate
方法即可完成认证。Spring Security默认的认证方式就是在 UsernamePasswordAuthenticationFilter
这个过滤器中进行认证的,该过滤器负责认证逻辑。
Spring Security用户认证关键代码如下:
// 生成一个包含账号密码的认证信息
Authentication authenticationToken = new UsernamePasswordAuthenticationToken(username, passwrod);
// AuthenticationManager校验这个认证信息,返回一个已认证的Authentication
Authentication authentication = authenticationManager.authenticate(authenticationToken);
// 将返回的Authentication存到上下文中
SecurityContextHolder.getContext().setAuthentication(authentication);
下面我们来分析一下。
2.1、认证接口分析
AuthenticationManager
的校验逻辑非常简单:
根据用户名先查询出用户对象(没有查到则抛出异常)将用户对象的密码和传递过来的密码进行校验,密码不匹配则抛出异常。
这个逻辑没啥好说的,再简单不过了。重点是这里每一个步骤Spring Security都提供了组件:
** 1、是谁执行 根据用户名查询出用户对象 逻辑的呢?用户对象数据可以存在内存中、文件中、数据库中,你得确定好怎么查才行。这一部分就是交由 UserDetialsService
** 处理,该接口只有一个方法 loadUserByUsername(String username)
,通过用户名查询用户对象,默认实现是在内存中查询。
** 2、那查询出来的 用户对象 又是什么呢?每个系统中的用户对象数据都不尽相同,咱们需要确认我们的用户数据是啥样的才行。Spring Security中的用户数据则是由 UserDetails
** 来体现,该接口中提供了账号、密码等通用属性。
** 3、对密码进行校验大家可能会觉得比较简单,if、else
搞定,就没必要用什么组件了吧?但框架毕竟是框架考虑的比较周全,除了 if、else
外还解决了密码加密的问题,这个组件就是 PasswordEncoder
**,负责密码加密与校验。
我们可以看下 AuthenticationManager
校验逻辑的大概源码:
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
...省略其他代码
// 传递过来的用户名
String username = authentication.getName();
// 调用UserDetailService的方法,通过用户名查询出用户对象UserDetail(查询不出来UserDetailService则会抛出异常)
UserDetails userDetails = this.getUserDetailsService().loadUserByUsername(username);
String presentedPassword = authentication.getCredentials().toString();
// 传递过来的密码
String password = authentication.getCredentials().toString();
// 使用密码解析器PasswordEncoder传递过来的密码是否和真实的用户密码匹配
if (!passwordEncoder.matches(password, userDetails.getPassword())) {
// 密码错误则抛出异常
throw new BadCredentialsException("错误信息...");
}
// 注意哦,这里返回的已认证Authentication,是将整个UserDetails放进去充当Principal
UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(userDetails,
authentication.getCredentials(), userDetails.getAuthorities());
return result;
...省略其他代码
}
UserDetialsService
、UserDetails
、PasswordEncoder
,这三个组件Spring Security都有默认实现,这一般是满足不了我们的实际需求的,所以这里我们自己来实现这些组件!