logo头像

From zero to HERO

Spring Security 实战干货:SecurityContext相关的知识

1. 前言

欢迎阅读 Spring Security 实战干货 系列文章 。在前两篇我们讲解了 基于配置基于注解 来配置访问控制。今天我们来讲一下如何在接口访问中检索当前认证用户信息。
我们先讲一下具体的场景。通常我们在认证后访问需要认证的资源时需要获取当前认证用户的信息。比如 “查询我的个人信息”。如果你直接在接口访问时显式的传入你的 UserID 肯定是不合适的。因为你认证通过后访问资源,系统是知道你是谁的。而且显式的暴露用户的检索接口也不安全。所以我们需要一个业务中可以检索当前认证用户的工具。 接下来我们来看看 Spring Security 是如何解决这个痛点的。

2. 安全上下文 SecurityContext

不知道你有没有留意Spring Security 实战干货:使用 JWT 认证访问接口 中是如何实现 JWT 认证拦截器 JwtAuthenticationFilter 。当服务端对 JWT Token 认证通过后,会将认证用户的信息封装到 UsernamePasswordAuthenticationToken 中 并使用工具类放入安全上下文 SecurityContext 中,当服务端响应用户后又使用同一个工具类将 UsernamePasswordAuthenticationTokenSecurityContextclear 掉。
我们来简单了解 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. 总结

SecurityContextSpring Security 中的一个非常重要类,今天不但介绍 SecurityContext 是什么、有什么作用,也对以前讲过的一些知识进行回顾。
也对如何使用 SecurityContextHolder 操作 SecurityContext 进行了讲解。最后也简单讲述了 SecurityContextHolder 三种存储 SecurityContext 的策略和使用场景 。希望对你学习 Spring Security 有帮助。还请多多关注。

评论系统未开启,无法评论!