mirror of
				https://github.com/spring-projects/spring-security.git
				synced 2025-10-31 14:48:54 +00:00 
			
		
		
		
	
		
			
	
	
		
			161 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			161 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|  | [[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 | ||
|  |     } | ||
|  | } | ||
|  | ---- | ||
|  | ==== |