java - SecurityContextHolder 不是一个 Bean 吗?

标签 java spring spring-boot authentication spring-security

尝试 Autowiring SecurityContextHolder 我收到错误

required a bean of type 'org.springframework.security.core.context.SecurityContextHolder' that could not be found.

事实证明它可以从代码的任何部分使用,例如

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

为什么它不是一个 bean,它是如何在幕后初始化的? 是否有其他类似的静态实用程序类可以从任何地方使用以及如何找到它们?

最佳答案

SecurityContextHolder 是一个实用程序类,它声明了一堆 static方法,可以使用类名访问。

实例化实用程序类没有多大意义(为了强调这一点,它们的构造函数通常是私有(private)的),因此 SecurityContextHolder不是上下文中的 Bean,因此无法(也不需要)注入(inject)它。

目的SecurityContextHolder方便访问 SecurityContext ,其中包含特定于当前经过身份验证的用户的信息。另外,SecurityContextHolder提供各种管理策略SecurityContext :

  • MODE_THREADLOCAL是默认的,适用于所谓的基于 servlet 的 Web 应用程序,该应用程序使用每个请求线程模型。在这种情况下,每个线程都有自己的上下文,Spring 使用 TreadLocal 管理上下文。
  • MODE_INHERITABLETHREADLOCAL与前一个类似,但有一个区别 - 它允许每个请求使用多个线程,如果我们生成一个新线程,它会继承父线程的上下文。
  • MODE_GLOBAL - 不适合服务器使用。该策略并非基于TreadLocal ,每个线程都应该看到相同的上下文。并且可以在独立应用程序中使用(例如在 Swing 客户端中)。

这是 Spring Security documentation 的简短引用(如果您想了解更多信息,请仔细查看此链接):

10.1. SecurityContextHolder

At the heart of Spring Security’s authentication model is the SecurityContextHolder. It contains the SecurityContext. securitycontextholder

enter image description here

The SecurityContextHolder is where Spring Security stores the details of who is authenticated. Spring Security does not care how the SecurityContextHolder is populated. If it contains a value, then it is used as the currently authenticated user.

...

因此,回顾一下 SecurityContextHolder 的主要目的就是管理SecurityContext 。安全上下文旨在提供对用户的 Authentication 的访问.

Authentication代表当前经过身份验证的用户。自从 Authentication一个 Bean,它可以通过另一个 Bean 中的依赖注入(inject)来提供,例如作为方法参数。

让我们看一个例子。假设我们有一个 Controller ,其端点返回 Foo 的实例这需要 Authentication 中的一些用户信息:

@RestController
public class FooController {
    
    @GetMapping("/foo")
    Foo getFoo(Authentication a) {
        
        return FooUtils.generateFoo(a);
    }
}

它利用generateFoo()方法通过传递 Authentication注入(inject)了一个参数。方法generateFoo()位于FooUtils这是一个实用程序类。

public class FooUtils {
    public static Foo generateFoo(Authentication a) {
        
        return new Foo(a.getPrincipal());
    }
}

Authentication无法注入(inject) FooUtils 的方法中,因为它不是 Bean,因此它是由调用者分发的。如果我们想象调用链会更长,即调用端点方法和FooUtils.generateFoo()之间会有更多操作。路过的话不太方便Authentication通过几种不会使用它的方法。

相反,可以使用 SecurityContextHolder并获得Authentication就在 FooUtils 内:

public class FooUtils {
    public static Foo generateFoo() {
        Authentication a = SecurityContextHolder
            .getContext()
            .getAuthentication();
        
        return new Foo(a.getPrincipal());
    }
}

关于java - SecurityContextHolder 不是一个 Bean 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74458719/

相关文章:

java - 如何设置数据绑定(bind)中包含布局的可见性?

java - 连接到 StompClient 时我可能在哪里出错?

java - spring webmvc框架中的TransactionRequiredException

java - 即使设置了 spring.expression.compiler.mode,Spring SpEL 也不会编译

java - 更改组合框时尝试在 jpanel 中给出不同的 "screens"

Java从二进制到八进制的转换

java - 为什么在Controller注解中使用@Component

java - CompletableFuture VS @Async

java - Spring 重试 : method annotated with @Recover not being called

java - Eclipse 中的 Struts 2 给出 "requested resource not found"