Home > database >  Isn't SecurityContextHolder a Bean?
Isn't SecurityContextHolder a Bean?

Time:11-18

Trying to Autowire SecurityContextHolder I get error

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

Turns out that it is available from any part of the code like

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

How come it isn't a bean and how does it get initialized under the hood? Are there other static utility classes like that available to be consumed from anywhere and how do I find them?

CodePudding user response:

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.

...

So, as a recap, the main purpose of SecurityContextHolder is to manage SecurityContext. And security context is meant to provide access to the user's Authentication.

Authentication represents the currently authenticated user. And since Authentication a Bean, it can be provided through dependency injection in another Bean, for instance as a method parameter.

Let's have a look at an example. Assume we have a controller which has an endpoint returning an instance of Foo which requires some user's information from the Authentication:

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

It makes use of the generateFoo() method by passing Authentication injected a parameter. Method generateFoo() located in the FooUtils which is a utility class.

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

Authentication can't be injected in the methods of FooUtils, since it's a not a Bean, therefore it's being handed out by the caller. If we imagine that chain of calls would be longer, i.e. there would be more actions in between the calling endpoint method and FooUtils.generateFoo() it would not be very convenient to pass around Authentication through several methods where it's not going to be used.

Instead, can make use of the SecurityContextHolder and obtain Authentication right on the spot inside the FooUtils:

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