Spring Security 主要类解释
参考出处
老徐Spring Security(一)--Architecture Overview](https://www.cnkirito.moe/spring-security-1/)
SecurityContextHolder
SecurityContextHolder 用来保存安全上下文,简单理解就是登陆的用户信息。包括用户是谁,角色权限等。它是通过 ThreadLocal 保存认证信息的,那么就意味着它与线程绑定。Spring Security 在用户登录时自动绑定认证信息到当前线程,用户退出时,自动清除当前线程的认证信息,这一前提是我们是在 web 场景下使用 Spring Security,而如果是 Swing 程序,需要替换 SecurityContextHolder 的策略。
Authentication
Authentication是一个接口,直接继承了Principal和Serializable,而Principal是位于java.security包中的,Authentication又是 Spring Security 中的接口,所以Authentication是在 Spring Security 中最高级别的身份/认证的抽象了。Authentication中的方法,我们可以看到有权限集合,密码,用户细节信息,用户信息,是否认证。
- getAuthorities() ,权限信息集合
- getCredentials(),密码信息,用户输入的密码字符串,在认证过后通常会被移除
- getDetails(),细节信息,web 应用中通常为 WebAuthenticationDetails,记录了访问者的 IP 和 sessionId 的值
- getPrincipal(),最最重要的身份信息,大部分情况下返回的是 UserDetail 接口的实现类。
- isAuthenticated(),是否被认证
认证流程
用户名和密码被过滤器获取到,封装成
Authentication,通常情况下是UsernamePasswordAuthenticationToken这个实现类由
AuthenticationManager身份管理器负责验证这个Authentication,简单理解为看看账号密码是否正确认证成功后,
AuthenticationManager身份管理器返回一个包含权限、身份信息的Authentication实例。不过密码通常会被移除掉SecurityContextHolder持有该Authentication的实例
AuthenticationManager
AuthenticationManager、 ProviderManager 、AuthenticationProvider 这三者经常会把我们搞得晕头转向,这里我们梳理一下。
AuthenticationManger是一个接口,它是认证功能的核心接口,也是发起认证的出发点,他之所以是接口的原因是,我们通常会是用户名+密码登录,但也会有手机号+密码,邮箱+密码等,甚至再抽象一点,指纹,虹膜都可以,所以AuthenticationManager是一个接口。ProviderManager是一个类,它就是上面说的AuthenticationManager的一个实现类,那么它自然而然的就是来实现对不同的登录方式认证的逻辑,但这里需要说一下的是,个人的理解我们需要把上面说到的用户名+密码、手机号+密码、邮箱+密码这三种方式归为一个大类,或者说对应一个账号密码的ProviderManager,而像指纹、虹膜等又可以归为另一个大类即生物特征的ProviderManager。AuthenticationProvider是大类中的小类认证方式,在ProviderManager类中内部会维护一个List<AuthenticationProvider>列表,存放多种认证方式,其实这就是委托者模式(Delegate)。
在 ProviderManager 中的整个认证过程其实就是,按照 List<AuthenticationProvider> 依次去认证,认证成功就直接返回,认证失败的话就会继续下一个 AuthenticationProvider,如果全都无法认证,那 ProviderManager 会抛出一个 ProviderNotFoundException 的异常。
DaoAuthenticationProvider
这是一个最常用的 AuthenticationProvider,根据类型我们能猜出来大概,这是一个从数据库查出数据库,来进行认证的一个实现。
在不讨论框架的情况下,我们的思路流程基本都是,用户前台提交用户名和密码,而数据库保存了用户名和密码,认证就是用前台提交的用户名去数据库找到对应的用户名以及密码,在对比密码是否相同或就可以了。
在 Spring Security 中前台提交的用户名和密码,被封装成了 UsernamePasswordAuthenticationToken,根据用户名加载用户的功能则交给了 UserDetailsService,在 DaoAuthenticationProvider 中还有一个 retrieveUser 方法,虽然有两个参数,但是我们可以可以只看第一个参数 username,整个方法会返回一个 UserDetails。然后还剩下密码的对比,这个交由 additionalAuthenticationChecks 方法来进行,它的逻辑是如果认证失败就抛出异常,然后就是默认通过,因为他的方法返回值是 void。
UserDtails 与 UserDetailsService
UserDetails 接口代表了最详细的用户信息,它与 Authentication 接口很类似,需要注重注意的是 Authentication 的 getCredentials() 与 UserDetail 中的 getPassword() 在理解上不一样,前者是用户提交的密码凭证(可以理解为只是一个凭证,还不知道它是否是正确的密码),而后者是用户正确的密码。Authentication 中的 getAuthorities()实际上是由 UserDetails 的 getAuthorities() 传递而形成的。
UserDetailsService 和 AuthenticationProvider 的区别其实很简单,UserDetailService 只是从特定的地方(一般是数据库)加载用户信息,然后就没了。
评论