使用Spring Security的静态方法获取当前用户详细信息

问题描述 投票:2回答:1

我有一个需求,想获取当前已经登录的用户的详细信息。为了获得该用户的详细信息,我们可以使用 SecurityContextHolder.getContext() 并提取细节。根据:


SecurityContextHolder,SecurityContext和认证对象。

默认情况下, SecurityContextHolder 使用 ThreadLocal 来存储这些细节,这意味着安全上下文始终可供在 一脉相承. 使用 ThreadLocal 这样一来 quite safe if care is taken to clear the thread after the present principal’s request is processed. 当然,Spring Security会自动为您处理这些问题,所以无需担心。


在请求之间存储SecurityContext

在Spring Security中,负责存储的是 SecurityContext 在请求之间,属于 SecurityContextPersistenceFilter,它默认将上下文存储为一个 HttpSession 间的属性 HTTP请求. 它将上下文恢复到 SecurityContextHolder 对于每项请求,关键是。当请求完成时,清除SecurityContextHolder。

许多其他类型的应用(例如,a) 无状态的RESTful web服务)不使用 HTTP会话,并将在每次请求时重新进行身份验证。. 然而,仍然重要的是 SecurityContextPersistenceFilter 包括在链中,以确保。SecurityContextHolder 每次请求后都会被清除。


问题是

我需要在服务层的多个地方返回基于用户权限的用户详细信息,所以我们有一个静态方法来返回这些详细信息。该项目由REST API和会话创建策略组成,具体如下 SessionCreationPolicy.STATELESSSecurityContextHolderStrategy 作为 ThreadLocal. 服务层包括 @Transactional.

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

  • Spring Security将如何管理 SecurityContextPersistenceFilter 对于 STATELESS 应用,是否需要手动配置?
  • 是否可以使用 SecurityContextHolderStrategy 作为 ThreadLocal?
  • 是否有可能因为 ThreadLocal 策略和静态方法?

环境。

框架:Spring Boot ORM:Hibernate Spring Boot ORM: Hibernate Database: Postgres架构。单片机(即将迁移到微服务)

如有需要,我会补充更多细节


UPDATE。

感谢@Macro,如前所述,为 SessionCreationPolicy.STATELESS,

SessionManagementConfigurer 包括 isStateless() 方法,返回 真正 为无状态策略。在此基础上,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 作为 ThreadLocal

服务层 包括 @Transactional.

java spring spring-boot spring-security static
1个回答
1
投票

设置

.sessionManagement()
     .sessionCreationPolicy(SessionCreationPolicy.STATELESS)

将导致Spring安全使用一个 NullSecurityContextRepository而不是默认的 HttpSessionSecurityContextRepository.

它是一个简单的实现,因为它不会简单地保存任何东西到HTTP Session中,并为每个请求创建一个完全的 new and empty SecurityContext,因此没有存储认证等。

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

SecurityContextPersistenceFilter就像HttpSessionRepository一样工作,不需要其他手动配置。

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

是的,这就是使用它们的目的,而且这也是默认的策略。所以,每个线程都有自己的SecurityContext认证对象。你是用静态方法访问ThreadLocal,因此没有机会访问 "错误的 "用户信息。在你的用例中使用 "GlocalSecurityContextHolderStrategy "会有问题,但无论如何,这不是你正在做的事情。

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

© www.soinside.com 2019 - 2024. All rights reserved.