I have a project, where I have user roles, based on their language.
For example, I have MODERATOR
roles, which are set based on what languages they speak, for example, MODERATOR_en_GB
, or MODERATOR_en_US
.
On a given API end-point I would like to check whether the user has the MODERATOR_language_REGION
role - the language_REGION
comes as a parameter on that end-point.
But I don't know how to use the @PreAuthorize(hasAnyRole)
function, with this kind of dynamic role.
My MODERATOR
enum looks like this:
public static enum MODERATOR {
en_US("ROLE_MODERATOR_en_US"),
en_GB("ROLE_MODERATOR_en_GB");
private final String role;
MODERATOR(String role) {
this.role = role;
}
public String getRole() {
return role;
}
};
Then, I have my API endpoint like so:
@PreAuthorize("hasAnyRole('" MODERATOR "', '" ADMIN "')")
@GetMapping("/edit")
public List<PostsDto> getPostsForEdit(@RequestParam(required = false, defaultValue = "en_GB") Language language,
@PageableDefault(sort = "skippedCount") Pageable pageable) {
... some code
}
Obviously, this does not work, since MODERATOR
is an enum.
So I tried to do something like this:
@PreAuthorize("hasAnyRole(MODERATOR.valueOf(#language), '" ADMIN "')")
What I did here, was to try and use the language
parameter from the API end-point on the @PreAuthorize(hasAnyRole)
function.
In the same way, they use the #foo
in the example from here: https://www.baeldung.com/spring-security-create-new-custom-security-expression#3-example-in-practice
Any help would be greatly appreciated.
CodePudding user response:
Using SpeL you can invoke a bean and pass the parameters to the bean method, you could pass the locale
and the Authentication
objects, as well as the expected role.
@Service
public class AuthorizationService {
public boolean hasRoleLocale(String locale, Authentication authentication, String expectedRole) {
authentication.getAuthorities(); // Use to check the authorities/roles
expectedRole request.getLocale() // Use the locale from the request
// Do the business requirement for the authorization
}
}
And, in your Controller, you can do like:
@PreAuthorize("@authorizationService.hasRoleLocale(locale, authentication, 'MODERATOR')")
CodePudding user response:
Do you have MethodSecurity enabled?
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
CustomMethodSecurityExpressionHandler expressionHandler =
new CustomMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new CustomPermissionEvaluator());
return expressionHandler;
}
}