当前位置:网站首页>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 2343. 裁剪数字后查询第 K 小的数字 暴力+语法考察
6. Unified logging
数学工具-desmos 图形曲线
Codeforces Round #624 (Div. 3)
LeetCode 2354. 优质数对的数目 二进制01表示和集合之间的转换
unity-shader(中级)
第二十八章:解题技巧
求解斐波那契数列的若干方法
shader入门精要3
【线程网络】了解线程属性(fork/interview question)
我的2021回忆录
LeetCode 2353. 设计食物评分系统 维护哈希表+set
Server-Sent Events 一种轻量级的Push方式
Unity中事件的3种实现方法
剑指offer:删除链表中重复的节点
饥荒联机版Mod开发——配置代码环境(二)
关于分布式的一些知识点
极简式 Unity 获取 bilibili 直播弹幕、SC、上舰、礼物等 插件
泰伯效应的建模
golang-reflect-method-callback