Spring Security 实战干货:SecurityContext相关的知识
1. 前言
欢迎阅读 Spring Security 实战干货[1] 系列文章 。在前两篇我们讲解了 基于配置[2] 和 基于注解[3] 来配置访问控制。今天我们来讲一下如何在接口访问中检索当前认证用户信息。我们先讲一下具体的场景。通常我们在认证后访问需要认证的资源时需要获取当前认证用户的信息。比如 “查询我的个人信息”。如果你直接在接口访问时显式的传入你的 UserID 肯定是不合适的。因为你认证通过后访问资源,系统是知道你是谁的。而且显式的暴露用户的检索接口也不安全。所以我们需要一个业务中可以检索当前认证用户的工具。接下来我们来看看 Spring Security 是如何解决这个痛点的。文末现金抽奖福利!
2. 安全上下文 SecurityContext
不知道你有没有留意Spring Security 实战干货:使用 JWT 认证访问接口[4] 中是如何实现 JWT 认证拦截器 JwtAuthenticationFilter
。当服务端对 JWT Token 认证通过后,会将认证用户的信息封装到 UsernamePasswordAuthenticationToken
中 并使用工具类放入安全上下文 SecurityContext
中,当服务端响应用户后又使用同一个工具类将 UsernamePasswordAuthenticationToken
从 SecurityContext
中 clear
掉。我们来简单了解 SecurityContext
具体是个什么东西。
package org.springframework.security.core.context;
import java.io.Serializable;
import org.springframework.security.core.Authentication;
public interface SecurityContext extends Serializable {
Authentication getAuthentication();
void setAuthentication(Authentication var1);
}
从源码上来看很简单就是一个 存储 Authentication
的容器。而 Authentication
是一个用户凭证接口用来作为用户认证的凭证使用,通常常用的实现有 认证用户 UsernamePasswordAuthenticationToken
和 匿名用户AnonymousAuthenticationToken
。其中 UsernamePasswordAuthenticationToken
包含了 UserDetails
, AnonymousAuthenticationToken
只包含了一个字符串 anonymousUser
作为匿名用户的标识。我们通过 SecurityContext
获取上下文时需要来进行类型判断。接下来我们来聊聊操作 SecurityContext
的工具类。
3. SecurityContextHolder
这个工具类就是 SecurityContextHolder
。它提供了两个有用的方法:
setContext 设置当前的 SecurityContext
getContext 获取当前的 SecurityContext
, 进而你可以获取到当前认证用户。clearContext 清除当前的 SecurityContext
平常我们通过这三个方法来操作安全上下文 SecurityContext
。你可以直接在代码中使用工具类 SecurityContextHolder
获取用户信息,像下面一样:
public String getCurrentUser() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication instanceof AnonymousAuthenticationToken){
return "anonymousUser";
}
UserDetails principal = (UserDetails) authentication.getPrincipal();
return principal.getUsername();
}
通过上面的自定义方法就可以解析到 UserDetails
的用户信息,你可以扩展 UserDetails
使得信息符合你的业务需要。上面方法中的判断是必须的,如果是匿名用户(AnonymousAuthenticationToken
)返回的 Principal
类型是一个字符串 anonymousUser
。
3.1 扩展知识:SecurityContextHolder 存储策略
这里也扩展一下知识面,简单讲一下 SecurityContextHolder
是如何存储 SecurityContext
的。SecurityContextHolder
默认有三种存储 SecurityContext
的策略:
MODE_THREADLOCAL 利用 ThreadLocal
机制来保存每个使用者的SecurityContext
,缺省策略,平常我们使用这个就行了。MODE_INHERITABLETHREADLOCAL 利用 InheritableThreadLocal
机制来保存每个使用者的SecurityContext
。多用于多线程环境环境下。MODE_GLOBAL 静态机制,作用域为全局。目前不太常用。
4. 总结
SecurityContext
是 Spring Security 中的一个非常重要类,今天不但介绍 SecurityContext
是什么、有什么作用,也对以前讲过的一些知识进行回顾。也对如何使用 SecurityContextHolder
操作 SecurityContext
进行了讲解。后也简单讲述了 SecurityContextHolder
三种存储 SecurityContext
的策略和使用场景 。希望对你学习 Spring Security 有帮助。还请多多关注
参考资料
Spring Security 实战干货: https://www.felord.cn/categories/spring-security/
[2]基于配置: https://www.felord.cn/spring-security-javaconfig-rbac.html
[3]基于注解: https://www.felord.cn/spring-security-annotation-rbac.html
[4]使用 JWT 访问接口: https://www.felord.cn/spring-security-jwt-authentication.html
相关文章