Add DefaultMethodSecurityExpressionHandler
Closes gh-12356
This commit is contained in:
parent
6bf11181ef
commit
35cf52d3bd
|
@ -104,6 +104,111 @@ should change to:
|
|||
----
|
||||
====
|
||||
|
||||
=== Use a Custom `@Bean` instead of subclassing `DefaultMethodSecurityExpressionHandler`
|
||||
|
||||
As a performance optimization, a new method was introduced to `MethodSecurityExpressionHandler` that takes a `Supplier<Authentication>` instead of an `Authentication`.
|
||||
|
||||
This allows Spring Security to defer the lookup of the `Authentication`, and is taken advantage of automatically when you use `@EnableMethodSecurity` instead of `@EnableGlobalMethodSecurity`.
|
||||
|
||||
However, let's say that your code extends `DefaultMethodSecurityExpressionHandler` and overrides `createSecurityExpressionRoot(Authentication, MethodInvocation)` to return a custom `SecurityExpressionRoot` instance.
|
||||
This will no longer work because the arrangement that `@EnableMethodSecurity` sets up calls `createEvaluationContext(Supplier<Authentication>, MethodInvocation)` instead.
|
||||
|
||||
Happily, such a level of customization is often unnecessary.
|
||||
Instead, you can create a custom bean with the authorization methods that you need.
|
||||
|
||||
For example, let's say you are wanting a custom evaluation of `@PostAuthorize("hasAuthority('ADMIN')")`.
|
||||
You can create a custom `@Bean` like this one:
|
||||
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
class MyAuthorizer {
|
||||
boolean isAdmin(MethodSecurityExpressionOperations root) {
|
||||
boolean decision = root.hasAuthority("ADMIN");
|
||||
// custom work ...
|
||||
return decision;
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
class MyAuthorizer {
|
||||
fun isAdmin(val root: MethodSecurityExpressionOperations): boolean {
|
||||
val decision = root.hasAuthority("ADMIN");
|
||||
// custom work ...
|
||||
return decision;
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
and then refer to it in the annotation like so:
|
||||
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@PreAuthorize("@authz.isAdmin(#root)")
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@PreAuthorize("@authz.isAdmin(#root)")
|
||||
----
|
||||
====
|
||||
|
||||
==== I'd still prefer to subclass `DefaultMethodSecurityExpressionHandler`
|
||||
|
||||
If you must continue subclassing `DefaultMethodSecurityExpressionHandler`, you can still do so.
|
||||
Instead, override the `createEvaluationContext(Supplier<Authentication>, MethodInvocation)` method like so:
|
||||
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Component
|
||||
class MyExpressionHandler extends DefaultMethodSecurityExpressionHandler {
|
||||
@Override
|
||||
public EvaluationContext createEvaluationContext(
|
||||
Supplier<Authentication> authentication, MethodInvocation mi) {
|
||||
StandardEvaluationContext context = (StandardEvaluationContext) super.createEvaluationContext(authentication, mi);
|
||||
MySecurityExpressionRoot root = new MySecurityExpressionRoot(authentication, invocation);
|
||||
root.setPermissionEvaluator(getPermissionEvaluator());
|
||||
root.setTrustResolver(new AuthenticationTrustResolverImpl());
|
||||
root.setRoleHierarchy(getRoleHierarchy());
|
||||
context.setRootObject(root);
|
||||
return context;
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Component
|
||||
class MyExpressionHandler: DefaultMethodSecurityExpressionHandler {
|
||||
override fun createEvaluationContext(val authentication: Supplier<Authentication>,
|
||||
val mi: MethodInvocation): EvaluationContext {
|
||||
val context = super.createEvaluationContext(authentication, mi) as StandardEvaluationContext;
|
||||
val root = new MySecurityExpressionRoot(authentication, invocation);
|
||||
root.setPermissionEvaluator(getPermissionEvaluator());
|
||||
root.setTrustResolver(new AuthenticationTrustResolverImpl());
|
||||
root.setRoleHierarchy(getRoleHierarchy());
|
||||
context.setRootObject(root);
|
||||
return context;
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
==== Opt-out Steps
|
||||
|
||||
If you need to opt-out of these changes, you can use `@EnableGlobalMethodSecurity` instead of `@EnableMethodSecurity`
|
||||
|
||||
[[servlet-replace-permissionevaluator-bean-with-methodsecurityexpression-handler]]
|
||||
=== Publish a `MethodSecurityExpressionHandler` instead of a `PermissionEvaluator`
|
||||
|
||||
|
|
Loading…
Reference in New Issue