@@ -88,6 +88,61 @@ public Function<Account, Mono<Boolean>> func() {
88
88
----
89
89
======
90
90
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
+
91
146
=== Customizing Authorization
92
147
93
148
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
236
291
237
292
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].
238
293
294
+ [[jc-reactive-method-security-custom-authorization-manager]]
239
295
[[custom-authorization-managers]]
240
296
=== Using a Custom Authorization Manager
241
297
@@ -361,20 +417,6 @@ companion object {
361
417
}
362
418
}
363
419
----
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
- ----
378
420
======
379
421
380
422
[TIP]
@@ -384,192 +426,6 @@ We expose `MethodSecurityExpressionHandler` using a `static` method to ensure th
384
426
385
427
You can also subclass xref:servlet/authorization/method-security.adoc#subclass-defaultmethodsecurityexpressionhandler[`DefaultMessageSecurityExpressionHandler`] to add your own custom authorization expressions beyond the defaults.
386
428
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
-
573
429
== EnableReactiveMethodSecurity
574
430
575
431
[tabs]
0 commit comments