Home > Mobile >  How to use @PreAuthorize with dynamic user roles?
How to use @PreAuthorize with dynamic user roles?

Time:04-11

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;
    }
}
  • Related