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

标签 java spring spring-boot spring-security static

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

SecurityContextHolder, SecurityContext and Authentication Objects

默认情况下,SecurityContextHolder使用 ThreadLocal存储这些详细信息,这意味着安全上下文始终可用于同一执行线程中的方法。使用 ThreadLocal这样是quite 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 ,默认情况下将上下文存储为 HttpSession HTTP 请求之间的属性。它将上下文恢复到 SecurityContextHolder对于每个请求,最重要的是,在请求完成时清除 SecurityContextHolder

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

问题是

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

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

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

  • 环境:

    框架:Spring Boot
    ORM: hibernate
    数据库: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());
        }
    

    session 管理
    .sessionManagement()
         .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    

    备注

    SecurityContextHolderStrategy 为 ThreadLocal
    服务层由@Transactional组成.

    最佳答案

    环境

    .sessionManagement()
         .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    

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

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

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

    SecurityContextPersistenceFilter will just work as with the HttpSessionRepository, there's no other manual configuration required.



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

    Yes, that's the whole point of using them and it's the default strategy anyway. So, every thread has its own SecurityContext / Authentication objects. You are accessing the ThreadLocal with your static method, hence there's no chance of accessing "wrong" user details. It would be a problem to use the "GlocalSecurityContextHolderStrategy" in your use-case, but that's not what you are doing, anyway.



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

    关于java - 使用 Spring Security 的静态方法获取当前用户详细信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61555559/

    相关文章:

    java - @RestController 和@Component 之间的细微差别

    java - 如何在 Spring Boot 的日志中尽早打印应用程序版本?

    java - Starter autoconfig bean 始终优先于自定义 autoconfig bean

    java - 如何通过 COM/native DLL 公开 Java?

    java - 如果 Spring MVC Controller 方法不返回值,返回什么?

    java - GWT 可以处理 Java Swing 吗?

    spring - 通过 @RequestMapping 更改 Spring MVC 中的 url 路径

    java - 获取所有可以处理 Intent.ACTION_MEDIA_BUTTON Android 13 API33 的 android 包

    java - 用 Java 绘制 X-Y 图

    spring - junit中的ContextConfiguration继承