parent
bdd5f86526
commit
ce720ad38e
|
@ -54,6 +54,7 @@
|
||||||
*** xref:servlet/authorization/secure-objects.adoc[Secure Object Implementations]
|
*** xref:servlet/authorization/secure-objects.adoc[Secure Object Implementations]
|
||||||
*** xref:servlet/authorization/method-security.adoc[Method Security]
|
*** xref:servlet/authorization/method-security.adoc[Method Security]
|
||||||
*** xref:servlet/authorization/acls.adoc[Domain Object Security ACLs]
|
*** xref:servlet/authorization/acls.adoc[Domain Object Security ACLs]
|
||||||
|
*** xref:servlet/authorization/events.adoc[Authorization Events]
|
||||||
** xref:servlet/oauth2/index.adoc[OAuth2]
|
** xref:servlet/oauth2/index.adoc[OAuth2]
|
||||||
*** xref:servlet/oauth2/login/index.adoc[OAuth2 Log In]
|
*** xref:servlet/oauth2/login/index.adoc[OAuth2 Log In]
|
||||||
**** xref:servlet/oauth2/login/core.adoc[Core Configuration]
|
**** xref:servlet/oauth2/login/core.adoc[Core Configuration]
|
||||||
|
|
|
@ -0,0 +1,160 @@
|
||||||
|
[[servlet-events]]
|
||||||
|
= Authorization Events
|
||||||
|
|
||||||
|
For each authorization that is denied, an `AuthorizationDeniedEvent` is fired.
|
||||||
|
Also, it's possible to fire and `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`:
|
||||||
|
|
||||||
|
====
|
||||||
|
.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:
|
||||||
|
|
||||||
|
====
|
||||||
|
.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:
|
||||||
|
|
||||||
|
====
|
||||||
|
.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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
====
|
Loading…
Reference in New Issue