You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
169 lines
4.8 KiB
169 lines
4.8 KiB
[[servlet-events]] |
|
= Authorization Events |
|
|
|
For each authorization that is denied, an `AuthorizationDeniedEvent` is fired. |
|
Also, it's possible to fire an `AuthorizationGrantedEvent` for authorizations that are granted. |
|
|
|
To listen for these events, you must first publish an `AuthorizationEventPublisher`. |
|
|
|
Spring Security's `SpringAuthorizationEventPublisher` will probably do fine. |
|
It comes publishes authorization events using Spring's `ApplicationEventPublisher`: |
|
|
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Bean |
|
public AuthorizationEventPublisher authorizationEventPublisher |
|
(ApplicationEventPublisher applicationEventPublisher) { |
|
return new SpringAuthorizationEventPublisher(applicationEventPublisher); |
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Bean |
|
fun authorizationEventPublisher |
|
(applicationEventPublisher: ApplicationEventPublisher?): AuthorizationEventPublisher { |
|
return SpringAuthorizationEventPublisher(applicationEventPublisher) |
|
} |
|
---- |
|
====== |
|
|
|
Then, you can use Spring's `@EventListener` support: |
|
|
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Component |
|
public class AuthenticationEvents { |
|
|
|
@EventListener |
|
public void onFailure(AuthorizationDeniedEvent failure) { |
|
// ... |
|
} |
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Component |
|
class AuthenticationEvents { |
|
|
|
@EventListener |
|
fun onFailure(failure: AuthorizationDeniedEvent?) { |
|
// ... |
|
} |
|
} |
|
---- |
|
====== |
|
|
|
[[authorization-granted-events]] |
|
== Authorization Granted Events |
|
|
|
Because ``AuthorizationGrantedEvent``s have the potential to be quite noisy, they are not published by default. |
|
|
|
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. |
|
|
|
You can create your own event publisher that filters success events. |
|
For example, the following publisher only publishes authorization grants where `ROLE_ADMIN` was required: |
|
|
|
[tabs] |
|
====== |
|
Java:: |
|
+ |
|
[source,java,role="primary"] |
|
---- |
|
@Component |
|
public class MyAuthorizationEventPublisher implements AuthorizationEventPublisher { |
|
private final ApplicationEventPublisher publisher; |
|
private final AuthorizationEventPublisher delegate; |
|
|
|
public MyAuthorizationEventPublisher(ApplicationEventPublisher publisher) { |
|
this.publisher = publisher; |
|
this.delegate = new SpringAuthorizationEventPublisher(publisher); |
|
} |
|
|
|
@Override |
|
public <T> void publishAuthorizationEvent(Supplier<Authentication> authentication, |
|
T object, AuthorizationDecision decision) { |
|
if (decision == null) { |
|
return; |
|
} |
|
if (!decision.isGranted()) { |
|
this.delegate.publishAuthorizationEvent(authentication, object, decision); |
|
return; |
|
} |
|
if (shouldThisEventBePublished(decision)) { |
|
AuthorizationGrantedEvent granted = new AuthorizationGrantedEvent( |
|
authentication, object, decision); |
|
this.publisher.publishEvent(granted); |
|
} |
|
} |
|
|
|
private boolean shouldThisEventBePublished(AuthorizationDecision decision) { |
|
if (!(decision instanceof AuthorityAuthorizationDecision)) { |
|
return false; |
|
} |
|
Collection<GrantedAuthority> authorities = ((AuthorityAuthorizationDecision) decision).getAuthorities(); |
|
for (GrantedAuthority authority : authorities) { |
|
if ("ROLE_ADMIN".equals(authority.getAuthority())) { |
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
} |
|
---- |
|
|
|
Kotlin:: |
|
+ |
|
[source,kotlin,role="secondary"] |
|
---- |
|
@Component |
|
class MyAuthorizationEventPublisher(val publisher: ApplicationEventPublisher, |
|
val delegate: SpringAuthorizationEventPublisher = SpringAuthorizationEventPublisher(publisher)): |
|
AuthorizationEventPublisher { |
|
|
|
override fun <T : Any?> publishAuthorizationEvent( |
|
authentication: Supplier<Authentication>?, |
|
`object`: T, |
|
decision: AuthorizationDecision? |
|
) { |
|
if (decision == null) { |
|
return |
|
} |
|
if (!decision.isGranted) { |
|
this.delegate.publishAuthorizationEvent(authentication, `object`, decision) |
|
return |
|
} |
|
if (shouldThisEventBePublished(decision)) { |
|
val granted = AuthorizationGrantedEvent(authentication, `object`, decision) |
|
this.publisher.publishEvent(granted) |
|
} |
|
} |
|
|
|
private fun shouldThisEventBePublished(decision: AuthorizationDecision): Boolean { |
|
if (decision !is AuthorityAuthorizationDecision) { |
|
return false |
|
} |
|
val authorities = decision.authorities |
|
for (authority in authorities) { |
|
if ("ROLE_ADMIN" == authority.authority) { |
|
return true |
|
} |
|
} |
|
return false |
|
} |
|
} |
|
---- |
|
======
|
|
|