当前位置:网站首页>Oauth2.0 补充
Oauth2.0 补充
2022-08-02 14:14:00 【zhangyu丶】
SecurityContextHolder
SecurityContextHolder
用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保存在 SecurityContextHolder 中。SecurityContextHolder
默认使用ThreadLocal
策略来存储认证信息。看到ThreadLocal
也就意味着,这是一种与线程绑定的策略。- Spring Security 在用户登录时自动绑定认证信息到当前线程,在用户退出时,自动清除当前线程的认证信息。但这一切的前提,是你在web场景下使用Spring Security。
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
String username = ((UserDetails)principal).getUsername();
} else {
String username = principal.toString();
}
- getAuthentication()返回了认证信息,再次 getPrincipal() 返回了身份信息,
- UserDetails便是Spring对身份信息封装的一个接口
Authentication
package org.springframework.security.core;// <1>
public interface Authentication extends Principal, Serializable {
// <1>
Collection<? extends GrantedAuthority> getAuthorities(); //权限信息列表,默认是GrantedAuthority接口的一些实现类,通常是代表权限信息的一系列字符串。
Object getCredentials();//密码信息,用户输入的密码字符串,在认证过后通常会被移除,用于保障安全。
Object getDetails();//细节信息,web应用中的实现接口通常为 WebAuthenticationDetails,它记录了访问者的ip地址和sessionId的值。
Object getPrincipal();//最重要的身份信息,大部分情况下返回的是UserDetails接口的实现类,也是框架中的常用接口之一。
boolean isAuthenticated();
void setAuthenticated(boolean var1) throws IllegalArgumentException;
}
AuthenticationManager
初次接触 Spring Security 的朋友相信会被AuthenticationManager
,ProviderManager
,AuthenticationProvider
…这么多相似的Spring认证类搞得晕头转向,但只要稍微梳理一下就可以理解清楚它们的联系和设计者的用意。
- AuthenticationManager(接口)是认证相关的核心接口,也是发起认证的出发点,因为在实际需求中,我们可能会允许用户使用用户名+密码登录,同时允许用户使用邮箱+密码,手机号码+密码登录,甚至,可能允许用户使用指纹登录
- 所以说 AuthenticationManager 一般不直接认证,AuthenticationManager接口的常用实现类
ProviderManager
内部会维护一个List<AuthenticationProvider>
列表,存放多种认证方式,实际上这是委托者模式的应用(Delegate)。 - 核心的认证入口始终只有一个:AuthenticationManager,不同的认证方式:用户名+密码(UsernamePasswordAuthenticationToken),邮箱+密码,手机号码+密码登录则对应了三个 AuthenticationProvider。
// 关键认证部分的ProviderManager源码如下:
public class ProviderManager implements AuthenticationManager, MessageSourceAware,
InitializingBean {
// 维护一个AuthenticationProvider列表
private List<AuthenticationProvider> providers = Collections.emptyList();
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
Class<? extends Authentication> toTest = authentication.getClass();
AuthenticationException lastException = null;
Authentication result = null;
// 依次认证
for (AuthenticationProvider provider : getProviders()) {
if (!provider.supports(toTest)) {
continue;
}
try {
result = provider.authenticate(authentication);
if (result != null) {
copyDetails(authentication, result);
break;
}
}
...
catch (AuthenticationException e) {
lastException = e;
}
}
// 如果有Authentication信息,则直接返回
if (result != null) {
if (eraseCredentialsAfterAuthentication && (result instanceof CredentialsContainer)) {
//移除密码
((CredentialsContainer) result).eraseCredentials();
}
//发布登录成功事件
eventPublisher.publishAuthenticationSuccess(result);
return result;
}
...
//执行到此,说明没有认证成功,包装异常信息
if (lastException == null) {
lastException = new ProviderNotFoundException(messages.getMessage(
"ProviderManager.providerNotFound",
new Object[] {
toTest.getName() },
"No AuthenticationProvider found for {0}"));
}
prepareException(lastException, authentication);
throw lastException;
}
}
ProviderManager
中的List,会依照次序去认证,认证成功则立即返回,若认证失败则返回null,下一个AuthenticationProvider会继续尝试认证,如果所有认证器都无法认证成功,则ProviderManager
会抛出一个ProviderNotFoundException异常。
Spring Security是如何完成身份认证的?
- 用户名和密码被过滤器获取到,封装成
Authentication
,通常情况下是UsernamePasswordAuthenticationToken
这个实现类。 AuthenticationManager
身份管理器负责验证这个Authentication
- 认证成功后,
AuthenticationManager
身份管理器返回一个被填充满了信息的(包括上面提到的权限信息,身份信息,细节信息,但密码通常会被移除)Authentication
实例。 SecurityContextHolder
安全上下文容器将第3步填充了信息的Authentication
,通过SecurityContextHolder.getContext().setAuthentication(…)方法,设置到其中。
Oauth2.0 常见异常
- UsernameNotFoundException:用户名未找到。
- BadCredentialsException:认证错误。可以用于密码错误、验证码错误等。
- RememberMeAuthenticationException:记住我 认证错误。 在登录中常常有 记住我 选项,因为这个地方导致的错误。
- AccountStatusException:用户账户状态异常。例如被封号之类的。
- NonceExpiredException:Nonce过期异常。
- AuthenticationCredentialsNotFoundException:SecurityContext中不存在Authentication异常。
- AuthenticationServiceException:认证服务异常。可能是后端数据库之类的出现问题等等情况。
- ProviderNotFoundException:Provider找不到异常。由ProviderManager抛出。
- SessionAuthenticationException:会话认证异常。通常是因为同一个用户打开了多个会话。
- InsufficientAuthenticationException:认证信息不足异常?可能是由于 记住我 选项引发的。
Oauth2.0 系列文章
以下是同步到语雀的、可读性好一点,CSDN 继续看的点专栏就好。
Oauth2.0 核心篇
Oauth2.0 安全性(以微信授权登陆为例)
Oauth2.0 认证服务器搭建
Oauth2.0 添加验证码登陆方式
Oauth2.0 资源服务器搭建
Oauth2.0 自定义响应值以及异常处理
Oauth2.0 补充
边栏推荐
猜你喜欢
随机推荐
光导布局设计工具
LeetCode 2354. 优质数对的数目 二进制01表示和集合之间的转换
5款最好用的免费3D建模软件(附下载链接)
Qt | 定时器的使用 QTimer
深入理解Mysql索引底层数据结构与算法
十天学习Unity3D脚本(一)九个回调
剑指offer:删除链表中重复的节点
Server-Sent Events 一种轻量级的Push方式
Codeforces Round #605 (Div. 3)
Test case exercises
光栅区域衍射级数和效率的规范
Redis common interview questions
7. Redis
TypeScript
Optisystem应用:光电检测器灵敏度建模
灵活的区域定义
MMD->Unity一站式解决方案
Problems related to prime numbers - small notes
golang-reflect-method-callback
使用1D-1D EPE的光波导布局设计工具