Skip to content

Commit fc3de5e

Browse files
committed
Rework Method Security Reactive Docs
1 parent 784e074 commit fc3de5e

File tree

1 file changed

+56
-200
lines changed
  • docs/modules/ROOT/pages/reactive/authorization

1 file changed

+56
-200
lines changed

docs/modules/ROOT/pages/reactive/authorization/method.adoc

Lines changed: 56 additions & 200 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,61 @@ public Function<Account, Mono<Boolean>> func() {
8888
----
8989
======
9090

91+
Method authorization is a combination of before- and after-method authorization.
92+
93+
[NOTE]
94+
====
95+
Before-method authorization is performed before the method is invoked.
96+
If that authorization denies access, the method is not invoked, and an `AccessDeniedException` is thrown.
97+
After-method authorization is performed after the method is invoked, but before the method returns to the caller.
98+
If that authorization denies access, the value is not returned, and an `AccessDeniedException` is thrown
99+
====
100+
101+
To recreate what adding `@EnableReactiveMethodSecurity(useAuthorizationManager=true)` does by default, you would publish the following configuration:
102+
103+
.Full Pre-post Method Security Configuration
104+
[tabs]
105+
======
106+
Java::
107+
+
108+
[source,java,role="primary"]
109+
----
110+
@Configuration
111+
class MethodSecurityConfig {
112+
@Bean
113+
BeanDefinitionRegistryPostProcessor aopConfig() {
114+
return AopConfigUtils::registerAutoProxyCreatorIfNecessary;
115+
}
116+
117+
@Bean
118+
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
119+
PreFilterAuthorizationReactiveMethodInterceptor preFilterInterceptor() {
120+
return new PreFilterAuthorizationReactiveMethodInterceptor();
121+
}
122+
123+
@Bean
124+
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
125+
AuthorizationManagerBeforeReactiveMethodInterceptor preAuthorizeInterceptor() {
126+
return AuthorizationManagerBeforeReactiveMethodInterceptor.preAuthorize();
127+
}
128+
129+
@Bean
130+
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
131+
AuthorizationManagerAfterReactiveMethodInterceptor postAuthorizeInterceptor() {
132+
return AuthorizationManagerAfterReactiveMethodInterceptor.postAuthorize();
133+
}
134+
135+
@Bean
136+
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
137+
PostFilterAuthorizationReactiveMethodInterceptor postFilterInterceptor() {
138+
return new PostFilterAuthorizationReactiveMethodInterceptor();
139+
}
140+
}
141+
----
142+
======
143+
144+
Notice that Spring Security's method security is built using Spring AOP.
145+
91146
=== Customizing Authorization
92147

93148
Spring Security's `@PreAuthorize`, `@PostAuthorize`, `@PreFilter`, and `@PostFilter` ship with rich expression-based support.
@@ -236,6 +291,7 @@ Note, though, that returning an object is preferred as this doesn't incur the ex
236291

237292
Then, you can access the custom details when you xref:servlet/authorization/method-security.adoc#fallback-values-authorization-denied[customize how the authorization result is handled].
238293

294+
[[jc-reactive-method-security-custom-authorization-manager]]
239295
[[custom-authorization-managers]]
240296
=== Using a Custom Authorization Manager
241297

@@ -361,20 +417,6 @@ companion object {
361417
}
362418
}
363419
----
364-
365-
Xml::
366-
+
367-
[source,xml,role="secondary"]
368-
----
369-
<sec:method-security>
370-
<sec:expression-handler ref="myExpressionHandler"/>
371-
</sec:method-security>
372-
373-
<bean id="myExpressionHandler"
374-
class="org.springframework.security.messaging.access.expression.DefaultMessageSecurityExpressionHandler">
375-
<property name="roleHierarchy" ref="roleHierarchy"/>
376-
</bean>
377-
----
378420
======
379421

380422
[TIP]
@@ -384,192 +426,6 @@ We expose `MethodSecurityExpressionHandler` using a `static` method to ensure th
384426

385427
You can also subclass xref:servlet/authorization/method-security.adoc#subclass-defaultmethodsecurityexpressionhandler[`DefaultMessageSecurityExpressionHandler`] to add your own custom authorization expressions beyond the defaults.
386428

387-
[[jc-reactive-method-security-custom-authorization-manager]]
388-
=== Custom Authorization Managers
389-
390-
Method authorization is a combination of before- and after-method authorization.
391-
392-
[NOTE]
393-
====
394-
Before-method authorization is performed before the method is invoked.
395-
If that authorization denies access, the method is not invoked, and an `AccessDeniedException` is thrown.
396-
After-method authorization is performed after the method is invoked, but before the method returns to the caller.
397-
If that authorization denies access, the value is not returned, and an `AccessDeniedException` is thrown
398-
====
399-
400-
To recreate what adding `@EnableReactiveMethodSecurity(useAuthorizationManager=true)` does by default, you would publish the following configuration:
401-
402-
.Full Pre-post Method Security Configuration
403-
[tabs]
404-
======
405-
Java::
406-
+
407-
[source,java,role="primary"]
408-
----
409-
@Configuration
410-
class MethodSecurityConfig {
411-
@Bean
412-
BeanDefinitionRegistryPostProcessor aopConfig() {
413-
return AopConfigUtils::registerAutoProxyCreatorIfNecessary;
414-
}
415-
416-
@Bean
417-
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
418-
PreFilterAuthorizationReactiveMethodInterceptor preFilterInterceptor() {
419-
return new PreFilterAuthorizationReactiveMethodInterceptor();
420-
}
421-
422-
@Bean
423-
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
424-
AuthorizationManagerBeforeReactiveMethodInterceptor preAuthorizeInterceptor() {
425-
return AuthorizationManagerBeforeReactiveMethodInterceptor.preAuthorize();
426-
}
427-
428-
@Bean
429-
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
430-
AuthorizationManagerAfterReactiveMethodInterceptor postAuthorizeInterceptor() {
431-
return AuthorizationManagerAfterReactiveMethodInterceptor.postAuthorize();
432-
}
433-
434-
@Bean
435-
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
436-
PostFilterAuthorizationReactiveMethodInterceptor postFilterInterceptor() {
437-
return new PostFilterAuthorizationReactiveMethodInterceptor();
438-
}
439-
}
440-
----
441-
======
442-
443-
Notice that Spring Security's method security is built using Spring AOP.
444-
So, interceptors are invoked based on the order specified.
445-
This can be customized by calling `setOrder` on the interceptor instances like so:
446-
447-
.Publish Custom Advisor
448-
[tabs]
449-
======
450-
Java::
451-
+
452-
[source,java,role="primary"]
453-
----
454-
@Bean
455-
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
456-
Advisor postFilterAuthorizationMethodInterceptor() {
457-
PostFilterAuthorizationMethodInterceptor interceptor = new PostFilterAuthorizationReactiveMethodInterceptor();
458-
interceptor.setOrder(AuthorizationInterceptorOrders.POST_AUTHORIZE.getOrder() - 1);
459-
return interceptor;
460-
}
461-
----
462-
======
463-
464-
You may want to only support `@PreAuthorize` in your application, in which case you can do the following:
465-
466-
.Only @PreAuthorize Configuration
467-
[tabs]
468-
======
469-
Java::
470-
+
471-
[source,java,role="primary"]
472-
----
473-
@Configuration
474-
class MethodSecurityConfig {
475-
@Bean
476-
BeanDefinitionRegistryPostProcessor aopConfig() {
477-
return AopConfigUtils::registerAutoProxyCreatorIfNecessary;
478-
}
479-
480-
@Bean
481-
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
482-
Advisor preAuthorize() {
483-
return AuthorizationManagerBeforeMethodInterceptor.preAuthorize();
484-
}
485-
}
486-
----
487-
======
488-
489-
Or, you may have a custom before-method `ReactiveAuthorizationManager` that you want to add to the list.
490-
491-
In this case, you will need to tell Spring Security both the `ReactiveAuthorizationManager` and to which methods and classes your authorization manager applies.
492-
493-
Thus, you can configure Spring Security to invoke your `ReactiveAuthorizationManager` in between `@PreAuthorize` and `@PostAuthorize` like so:
494-
495-
.Custom Before Advisor
496-
497-
[tabs]
498-
======
499-
Java::
500-
+
501-
[source,java,role="primary"]
502-
----
503-
@EnableReactiveMethodSecurity(useAuthorizationManager=true)
504-
class MethodSecurityConfig {
505-
@Bean
506-
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
507-
public Advisor customAuthorize() {
508-
JdkRegexpMethodPointcut pattern = new JdkRegexpMethodPointcut();
509-
pattern.setPattern("org.mycompany.myapp.service.*");
510-
ReactiveAuthorizationManager<MethodInvocation> rule = AuthorityAuthorizationManager.isAuthenticated();
511-
AuthorizationManagerBeforeReactiveMethodInterceptor interceptor = new AuthorizationManagerBeforeReactiveMethodInterceptor(pattern, rule);
512-
interceptor.setOrder(AuthorizationInterceptorsOrder.PRE_AUTHORIZE_ADVISOR_ORDER.getOrder() + 1);
513-
return interceptor;
514-
}
515-
}
516-
----
517-
======
518-
519-
[TIP]
520-
====
521-
You can place your interceptor in between Spring Security method interceptors using the order constants specified in `AuthorizationInterceptorsOrder`.
522-
====
523-
524-
The same can be done for after-method authorization.
525-
After-method authorization is generally concerned with analysing the return value to verify access.
526-
527-
For example, you might have a method that confirms that the account requested actually belongs to the logged-in user like so:
528-
529-
.@PostAuthorize example
530-
[tabs]
531-
======
532-
Java::
533-
+
534-
[source,java,role="primary"]
535-
----
536-
public interface BankService {
537-
538-
@PreAuthorize("hasRole('USER')")
539-
@PostAuthorize("returnObject.owner == authentication.name")
540-
Mono<Account> readAccount(Long id);
541-
}
542-
----
543-
======
544-
545-
You can supply your own `AuthorizationMethodInterceptor` to customize how access to the return value is evaluated.
546-
547-
For example, if you have your own custom annotation, you can configure it like so:
548-
549-
550-
.Custom After Advisor
551-
[tabs]
552-
======
553-
Java::
554-
+
555-
[source,java,role="primary"]
556-
----
557-
@EnableReactiveMethodSecurity(useAuthorizationManager=true)
558-
class MethodSecurityConfig {
559-
@Bean
560-
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
561-
public Advisor customAuthorize(ReactiveAuthorizationManager<MethodInvocationResult> rules) {
562-
AnnotationMethodMatcher pattern = new AnnotationMethodMatcher(MySecurityAnnotation.class);
563-
AuthorizationManagerAfterReactiveMethodInterceptor interceptor = new AuthorizationManagerAfterReactiveMethodInterceptor(pattern, rules);
564-
interceptor.setOrder(AuthorizationInterceptorsOrder.POST_AUTHORIZE_ADVISOR_ORDER.getOrder() + 1);
565-
return interceptor;
566-
}
567-
}
568-
----
569-
======
570-
571-
and it will be invoked after the `@PostAuthorize` interceptor.
572-
573429
== EnableReactiveMethodSecurity
574430

575431
[tabs]

0 commit comments

Comments
 (0)