【问题标题】:Using static methods with Spring Security to get current user details使用 Spring Security 的静态方法获取当前用户详细信息
【发布时间】:2023-04-03 19:00:01
【问题描述】:

我需要获取当前已登录用户的详细信息。要获取详细信息,我们可以使用SecurityContextHolder.getContext() 并提取详细信息。据了解,


SecurityContextHolder, SecurityContext and Authentication Objects

默认情况下,SecurityContextHolder 使用ThreadLocal 来存储这些详细信息,这意味着安全上下文始终可用于同一执行线程中的方法。以这种方式使用ThreadLocalquite safe if care is taken to clear the thread after the present principal’s request is processed。当然,Spring Security 会自动为您处理这些,因此您无需担心。


Storing the SecurityContext between requests

在 Spring Security 中,存储请求之间的SecurityContext 的责任落在了SecurityContextPersistenceFilter 上,它默认将上下文存储为HTTP 请求之间的HttpSession 属性。它将每个请求的上下文恢复到 SecurityContextHolder,并且至关重要的是,在请求完成时清除 SecurityContextHolder

许多其他类型的应用程序(例如,无状态 RESTful 网络服务)不使用 HTTP 会话,并且会在每个请求上重新进行身份验证。但是,将SecurityContextPersistenceFilter 包含在链中以确保在每次请求后清除SecurityContextHolder 仍然很重要。


问题是

我要求服务层多处的用户详细信息根据用户权限返回信息,所以我们有一个静态方法返回这些详细信息。该项目由 REST API 和会话创建策略组成,SessionCreationPolicy.STATELESSSecurityContextHolderStrategyThreadLocal。服务层由@Transactional 组成。

现在考虑对 API 的多个并发请求,

  • Spring Security 将如何为 STATELESS 应用程序管理 SecurityContextPersistenceFilter,是否需要手动配置?
  • 可以将SecurityContextHolderStrategy 用作ThreadLocal 吗?
  • 由于ThreadLocal 策略和静态方法,是否有可能获取错误/无效的用户详细信息?

环境:

框架:Spring Boot
ORM:休眠
数据库:Postgres
架构:单体(即将迁移到微服务)

如果需要,我会添加更多详细信息


更新:

感谢@Macro,如上所述,SessionCreationPolicy.STATELESS

SessionManagementConfigurerisStateless() 方法组成,该方法为无状态策略返回 true。基于该 http 设置共享对象为NullSecurityContextRepository 和请求缓存NullRequestCache。因此,HttpSessionSecurityContextRepository 中将没有可用的值。因此,使用静态方法的用户可能不会出现无效/错误详细信息的问题

  • SecurityContextHolderStrategy 是否对 MODE_INHERITABLETHREADLOCAL, MODE_THREADLOCAL 的用户详细信息有任何影响,因为 HttpSessionSecurityContextRepository 不会为共享对象设置任何值?

代码:

        if (stateless) {
            http.setSharedObject(SecurityContextRepository.class,
                    new NullSecurityContextRepository());
        }

        if (stateless) {
            http.setSharedObject(RequestCache.class, new NullRequestCache());
        }

代码:

获取用户详细信息的静态方法

    public static Optional<String> getCurrentUserLogin() {
        SecurityContext securityContext = SecurityContextHolder.getContext();
        return Optional.ofNullable(extractPrincipal(securityContext.getAuthentication()));
    }

    private static String extractPrincipal(Authentication authentication) {
        if (authentication == null) {
            return null;
        } else if (authentication.getPrincipal() instanceof UserDetails) {
            UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal();
            return springSecurityUser.getUsername();
        } else if (authentication.getPrincipal() instanceof String) {
            return (String) authentication.getPrincipal();
        }
        return null;
    }


    public static Optional<Authentication> getAuthenticatedCurrentUser() {
        log.debug("Request to get authentication for current user");
        SecurityContext securityContext = SecurityContextHolder.getContext();
        return Optional.ofNullable(securityContext.getAuthentication());
    }

会话管理

.sessionManagement()
     .sessionCreationPolicy(SessionCreationPolicy.STATELESS)

备注

SecurityContextHolderStrategy as ThreadLocal

服务层@Transactional组成。

【问题讨论】:

    标签: java spring spring-boot spring-security static


    【解决方案1】:

    设置

    .sessionManagement()
         .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    

    将导致 Spring Security 使用 NullSecurityContextRepository,而不是默认的 HttpSessionSecurityContextRepository

    这是一个简单的实现,因为它根本不会向 HTTP 会话保存任何内容,并且对于每个请求,都会创建一个完整的 new and empty SecurityContext,因此没有存储身份验证等。

    所以,回答你的第一个问题:

    SecurityContextPersistenceFilter 将与 HttpSessionRepository,无需其他手动配置。

    回答关于 Threadlocals 的第二个和第三个问题。

    是的,这就是使用它们的全部意义,而且它是默认设置 反正策略。因此,每个线程都有自己的 SecurityContext / Authentication 对象。您正在使用静态方法访问 ThreadLocal,因此不可能访问“错误”的用户详细信息。在您的用例中使用“GlocalSecurityContextHolderStrategy”将是一个问题,但无论如何,这不是您正在做的事情。

    另外,请记住,所有这些都与@Transactionals 无关。

    【讨论】:

      猜你喜欢
      • 2021-06-11
      • 1970-01-01
      • 2013-07-23
      • 2016-10-30
      • 1970-01-01
      • 2015-03-09
      • 1970-01-01
      • 2012-05-23
      • 2017-10-06
      相关资源
      最近更新 更多