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:
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());
}
}