events.adoc 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. [[servlet-events]]
  2. = Authorization Events
  3. For each authorization that is denied, an `AuthorizationDeniedEvent` is fired.
  4. Also, it's possible to fire and `AuthorizationGrantedEvent` for authorizations that are granted.
  5. To listen for these events, you must first publish an `AuthorizationEventPublisher`.
  6. Spring Security's `SpringAuthorizationEventPublisher` will probably do fine.
  7. It comes publishes authorization events using Spring's `ApplicationEventPublisher`:
  8. ====
  9. .Java
  10. [source,java,role="primary"]
  11. ----
  12. @Bean
  13. public AuthorizationEventPublisher authorizationEventPublisher
  14. (ApplicationEventPublisher applicationEventPublisher) {
  15. return new SpringAuthorizationEventPublisher(applicationEventPublisher);
  16. }
  17. ----
  18. .Kotlin
  19. [source,kotlin,role="secondary"]
  20. ----
  21. @Bean
  22. fun authorizationEventPublisher
  23. (applicationEventPublisher: ApplicationEventPublisher?): AuthorizationEventPublisher {
  24. return SpringAuthorizationEventPublisher(applicationEventPublisher)
  25. }
  26. ----
  27. ====
  28. Then, you can use Spring's `@EventListener` support:
  29. ====
  30. .Java
  31. [source,java,role="primary"]
  32. ----
  33. @Component
  34. public class AuthenticationEvents {
  35. @EventListener
  36. public void onFailure(AuthorizationDeniedEvent failure) {
  37. // ...
  38. }
  39. }
  40. ----
  41. .Kotlin
  42. [source,kotlin,role="secondary"]
  43. ----
  44. @Component
  45. class AuthenticationEvents {
  46. @EventListener
  47. fun onFailure(failure: AuthorizationDeniedEvent?) {
  48. // ...
  49. }
  50. }
  51. ----
  52. ====
  53. [[authorization-granted-events]]
  54. == Authorization Granted Events
  55. Because ``AuthorizationGrantedEvent``s have the potential to be quite noisy, they are not published by default.
  56. In fact, publishing these events will likely require some business logic on your part to ensure that your application is not inundated with noisy authorization events.
  57. You can create your own event publisher that filters success events.
  58. For example, the following publisher only publishes authorization grants where `ROLE_ADMIN` was required:
  59. ====
  60. .Java
  61. [source,java,role="primary"]
  62. ----
  63. @Component
  64. public class MyAuthorizationEventPublisher implements AuthorizationEventPublisher {
  65. private final ApplicationEventPublisher publisher;
  66. private final AuthorizationEventPublisher delegate;
  67. public MyAuthorizationEventPublisher(ApplicationEventPublisher publisher) {
  68. this.publisher = publisher;
  69. this.delegate = new SpringAuthorizationEventPublisher(publisher);
  70. }
  71. @Override
  72. public <T> void publishAuthorizationEvent(Supplier<Authentication> authentication,
  73. T object, AuthorizationDecision decision) {
  74. if (decision == null) {
  75. return;
  76. }
  77. if (!decision.isGranted()) {
  78. this.delegate.publishAuthorizationEvent(authentication, object, decision);
  79. return;
  80. }
  81. if (shouldThisEventBePublished(decision)) {
  82. AuthorizationGrantedEvent granted = new AuthorizationGrantedEvent(
  83. authentication, object, decision);
  84. this.publisher.publishEvent(granted);
  85. }
  86. }
  87. private boolean shouldThisEventBePublished(AuthorizationDecision decision) {
  88. if (!(decision instanceof AuthorityAuthorizationDecision)) {
  89. return false;
  90. }
  91. Collection<GrantedAuthority> authorities = ((AuthorityAuthorizationDecision) decision).getAuthorities();
  92. for (GrantedAuthority authority : authorities) {
  93. if ("ROLE_ADMIN".equals(authority.getAuthority())) {
  94. return true;
  95. }
  96. }
  97. return false;
  98. }
  99. }
  100. ----
  101. .Kotlin
  102. [source,kotlin,role="secondary"]
  103. ----
  104. @Component
  105. class MyAuthorizationEventPublisher(val publisher: ApplicationEventPublisher,
  106. val delegate: SpringAuthorizationEventPublisher = SpringAuthorizationEventPublisher(publisher)):
  107. AuthorizationEventPublisher {
  108. override fun <T : Any?> publishAuthorizationEvent(
  109. authentication: Supplier<Authentication>?,
  110. `object`: T,
  111. decision: AuthorizationDecision?
  112. ) {
  113. if (decision == null) {
  114. return
  115. }
  116. if (!decision.isGranted) {
  117. this.delegate.publishAuthorizationEvent(authentication, `object`, decision)
  118. return
  119. }
  120. if (shouldThisEventBePublished(decision)) {
  121. val granted = AuthorizationGrantedEvent(authentication, `object`, decision)
  122. this.publisher.publishEvent(granted)
  123. }
  124. }
  125. private fun shouldThisEventBePublished(decision: AuthorizationDecision): Boolean {
  126. if (decision !is AuthorityAuthorizationDecision) {
  127. return false
  128. }
  129. val authorities = decision.authorities
  130. for (authority in authorities) {
  131. if ("ROLE_ADMIN" == authority.authority) {
  132. return true
  133. }
  134. }
  135. return false
  136. }
  137. }
  138. ----
  139. ====