村亢 发表于 2025-6-2 22:52:39

SpringSecurity5(13-核心组件和认证流程)

SecurityContextHolder

SecurityContextHolder 持有的是安全上下文的信息,当前操作的用户是谁,用户是否已经被认证,他拥有哪些角色权限等,这些都被保存在 SecurityContextHolder 中。SecurityContextHolder 默认使用 ThreadLocal 策略来存储认证信息,在 web 环境下,SpringSecurity 在用户登录时自动绑定认证信息到当前线程,在用户退出时,自动清除当前线程的认证信息
public class SecurityContextHolder {

    // 三种工作模式的定义,每种工作模式对应一种策略
    public static final String MODE_THREADLOCAL = "MODE_THREADLOCAL";
    public static final String MODE_INHERITABLETHREADLOCAL = "MODE_INHERITABLETHREADLOCAL";
    public static final String MODE_GLOBAL = "MODE_GLOBAL";

    // 类加载时首先尝试从环境属性中获取所指定的工作模式
    public static final String SYSTEM_PROPERTY = "spring.security.strategy";       
    private static String strategyName = System.getProperty(SYSTEM_PROPERTY);
    private static SecurityContextHolderStrategy strategy;

    // 初始化计数器, 初始为 0,
    // 1. 类加载过程中会被初始化一次,此值变为 1
    // 2. 此后每次调用 setStrategyName 会对新的策略对象执行一次初始化,相应的该值会增 1
    private static int initializeCount = 0;

    static {
      initialize();
    }

    /**
   * 清除上下文
   */
    public static void clearContext() {
      strategy.clearContext();
    }

    /**
   * 获取上下文
   */
    public static SecurityContext getContext() {
      return strategy.getContext();
    }

    /**
   * 获取计数器的值
   */
    public static int getInitializeCount() {
      return initializeCount;
    }

    private static void initialize() {
      if (!StringUtils.hasText(strategyName)) {
            // Set default, 设置缺省工作模式/策略 MODE_THREADLOCAL
            strategyName = MODE_THREADLOCAL;
      }

      if (strategyName.equals(MODE_THREADLOCAL)) {
            strategy = new ThreadLocalSecurityContextHolderStrategy();
      } else if (strategyName.equals(MODE_INHERITABLETHREADLOCAL)) {
            strategy = new InheritableThreadLocalSecurityContextHolderStrategy();
      } else if (strategyName.equals(MODE_GLOBAL)) {
            strategy = new GlobalSecurityContextHolderStrategy();
      } else {
            // Try to load a custom strategy
            try {
                Class<?> clazz = Class.forName(strategyName);
                Constructor<?> customStrategy = clazz.getConstructor();
                strategy = (SecurityContextHolderStrategy) customStrategy.newInstance();
            }
            catch (Exception ex) {
                ReflectionUtils.handleReflectionException(ex);
            }
      }
      initializeCount++;
    }

    /**
   * 设置上下文
   */
    public static void setContext(SecurityContext context) {
      strategy.setContext(context);
    }

    /**
   * 设置工作模式
   */
    public static void setStrategyName(String strategyName) {
      SecurityContextHolder.strategyName = strategyName;
      initialize();
    }

    /**
   * 获取对应工作模式的策略
   */
    public static SecurityContextHolderStrategy getContextHolderStrategy() {
      return strategy;
    }

    /**
   * 创建空的上下文信息
   */
    public static SecurityContext createEmptyContext() {
      return strategy.createEmptyContext();
    }

    public String toString() {
      return "SecurityContextHolder[strategy='" + strategyName + "'; initializeCount="
                + initializeCount + "]";
    }
}SecurityContext

安全上下文,主要持有 Authentication 对象,如果用户未鉴权,那么 Authentication 对象将会是空的
public interface SecurityContext extends Serializable {
    /**
   * 获取当前经过身份验证的主体,或身份验证请求令牌
   */
    Authentication getAuthentication();

    /**
   * 更改当前经过身份验证的主体,或删除身份验证信息
   */
    void setAuthentication(Authentication authentication);
}Authentication

鉴权对象,该对象主要包含了用户的详细信息(UserDetails)和用户鉴权所需要的信息,如用户提交的用户名密码、Remember-me Token 或 digest hash 值等,按不同鉴权方式使用不同的 Authentication 实现
public interface Authentication extends Principal, Serializable {    //用来获取用户的权限。    Collection
页: [1]
查看完整版本: SpringSecurity5(13-核心组件和认证流程)