Spring Security customising method level authorization

If you’ve used Spring Security before you’ve probably used @Secured or @PreAuthorize annotations to enable method level security. These annotations are specifically useful for preventing your web applications being attacked by malicious users. Method level security makes sure that only authorized users can execute the specific method.

Depending upon the specific problem you can either use @Secured

 @Secured({ "ROLE_DBA","ROLE_ADMIN","ROLE_SUPER_ADMIN"})
void updateUser(){

//.....

}

Or you can use @PreAuthorize

@PreAuthorize("hasRole('ADMIN', 'ROLE_DBA', 'ROLE_SUPER_ADMIN')")
void updateUser(User user){

}

However, the limitation with the above annotations is that rely on GrantedAuthorities of the in session user. In other words, you are limited to the just the roles of the user to control the access to a specific method.

What about when you want to use another attribute, lets says a STATUS determined by an external service?

Or perhaps you have there is a reasonable amount to logic involved before deciding a particular user has access to a specific controller level method of your Spring app?

Under such circumstances you can leverage the ability to call custom methods through the @PreAuthorize annotation.  You can create a custom AccessManager spring managed bean (or something else suitably named for your app)

 


@Component("accessManager")
public class AccessManager{ 

	@Autowired
	MyThirdPartyService myThirdPartyService;

	public boolean hasAccess(Authentication authentication, String... statusesNotAllowed) {
	//Complex logic can be performed here.
	//1. Access user's data with the authentication object
	//2. Access third party service to access data not available (or shouldn't be part of) in the session
	//3. statusesNotAllowed an example paramter, can have more or less
	}
}

 

The AccessManager.hasAccess() method can be called in the @PreAuthorize annotation anywhere in your application. Only when AccessManager.hasAccess method returns true with the parameters specified in the annotation, the updateUser method would get executed.


@PreAuthorize("@accessManager.hasAccess(authentication, {'CANCELLED', 'BLOCKED', 'TERMINATED'})")
public String updateUser(User user){
	....
}