132

How to check user authority or permission in Java Code ? For example - I want to show or hide button for user depending on role. There are annotations like:

@PreAuthorize("hasRole('ROLE_USER')")

How to make it in Java code? Something like :

if(somethingHere.hasRole("ROLE_MANAGER")) {
   layout.addComponent(new Button("Edit users"));
}
Gajanan Kulkarni
  • 697
  • 6
  • 22
Piotr Gwiazda
  • 12,080
  • 13
  • 60
  • 91

20 Answers20

150

you can use the isUserInRole method of the HttpServletRequest object.

something like:

public String createForm(HttpSession session, HttpServletRequest request,  ModelMap   modelMap) {


    if (request.isUserInRole("ROLE_ADMIN")) {
        // code here
    }
}
gouki
  • 4,382
  • 3
  • 20
  • 20
76

Spring Security 3.0 has this API

SecurityContextHolderAwareRequestWrapper.isUserInRole(String role)

You'll have to inject the wrapper, before you use it.

SecurityContextHolderAwareRequestWrapper

WildDev
  • 2,250
  • 5
  • 35
  • 67
JoseK
  • 31,141
  • 14
  • 104
  • 131
  • 1
    This just do for-each lookup over auth.getAuthorities() It's easier to copy this code than construct or retreive SecurityContextHolderAwareRequestWrapper object. I'd rather wanted to use all security EL methods. For example hasPermission from ACL – Piotr Gwiazda Jun 11 '10 at 11:58
  • 58
    As your answer is stated, it looks like the method is static, however you need a `SecurityContextHolderAwareRequestWrapper` instance. You could improve it explaining how to obtain it and clarifying the answer itself a little bit more. – Aritz Feb 23 '15 at 09:59
  • 4
    How can I retrieve the wrapper in the Controller? – Alfonso Tienda Aug 04 '15 at 12:17
  • 4
    How can I get instance of SecurityContextHolderAwareRequestWrapper ? – gstackoverflow Sep 15 '15 at 12:10
  • 2
    Xtreme Biker is right, How do you get the SecurityContextHolderAwareRequestWrapper class? It's not a static object. – Try it Sep 25 '16 at 13:33
  • 6
    If this was a web app, which it looks like it's not, you could just add SecurityContextHolderAwareRequestWrapper as a parameter. And if it was a web app you could just declare HttpServletRequest as a parameter and call isUserInRole – David Bradley Sep 09 '18 at 03:34
  • 5
    Since people are confused on how to leverage this. The code in a controller looks like this. ```@RequestMapping(value = "/path/to/controller") public String sampleMethod(SecurityContextHolderAwareRequestWrapper requestWrapper, Model model){ //method code requestWrapper. isUserInRole("role"); } ``` – Dot Batch May 31 '19 at 20:53
  • You don't have to inject the entire SecurityContextHolderAwareRequestWrapper. Using javax.servlet.http.HttpServletRequest will suffice too. – GerardV Jan 17 '21 at 07:32
70

Instead of using a loop to find the authority from UserDetails you can do:

Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
boolean authorized = authorities.contains(new SimpleGrantedAuthority("ROLE_ADMIN"));
Alexander Kjäll
  • 4,246
  • 3
  • 33
  • 57
Ninca
  • 749
  • 5
  • 8
  • 2
    A much nicer answer, however the ROLE_ADMIN should be in double quotes. – Erica Kane Jan 18 '15 at 20:17
  • 8
    This is very risky. Be aware that switching to another implementation of GrantedAuthority implementation (eg. JAAS, by adding another authorization possibility) will make this code malfunction. See equals() implementation in SimpleGrantedAuthority – Petr Újezdský Apr 19 '16 at 12:35
53

You can retrieve the security context and then use that:

    import org.springframework.security.core.Authentication;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.context.SecurityContext;
    import org.springframework.security.core.context.SecurityContextHolder;

    protected boolean hasRole(String role) {
        // get security context from thread local
        SecurityContext context = SecurityContextHolder.getContext();
        if (context == null)
            return false;

        Authentication authentication = context.getAuthentication();
        if (authentication == null)
            return false;

        for (GrantedAuthority auth : authentication.getAuthorities()) {
            if (role.equals(auth.getAuthority()))
                return true;
        }

        return false;
    }
Nate Sammons
  • 631
  • 5
  • 3
14

You can implement a hasRole() method as below - (This is tested on spring security 3.0.x not sure about other versions.)

  protected final boolean hasRole(String role) {
    boolean hasRole = false;
    UserDetails userDetails = getUserDetails();
    if (userDetails != null) {
      Collection<GrantedAuthority> authorities = userDetails.getAuthorities();
      if (isRolePresent(authorities, role)) {
        hasRole = true;
      }
    } 
    return hasRole;
  }
  /**
   * Get info about currently logged in user
   * @return UserDetails if found in the context, null otherwise
   */
  protected UserDetails getUserDetails() {
    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    UserDetails userDetails = null;
    if (principal instanceof UserDetails) {
      userDetails = (UserDetails) principal;
    }
    return userDetails;
  }
  /**
   * Check if a role is present in the authorities of current user
   * @param authorities all authorities assigned to current user
   * @param role required authority
   * @return true if role is present in list of authorities assigned to current user, false otherwise
   */
  private boolean isRolePresent(Collection<GrantedAuthority> authorities, String role) {
    boolean isRolePresent = false;
    for (GrantedAuthority grantedAuthority : authorities) {
      isRolePresent = grantedAuthority.getAuthority().equals(role);
      if (isRolePresent) break;
    }
    return isRolePresent;
  }
Gopi
  • 10,073
  • 4
  • 31
  • 45
  • 1
    `SecurityContextHolder.getContext().getAuthentication()` can retrieve `null`. Maybe you add some check? – Mrusful Jan 20 '13 at 09:45
10

I'm using this:

@RequestMapping(method = RequestMethod.GET)
public void welcome(SecurityContextHolderAwareRequestWrapper request) {
    boolean b = request.isUserInRole("ROLE_ADMIN");
    System.out.println("ROLE_ADMIN=" + b);

    boolean c = request.isUserInRole("ROLE_USER");
    System.out.println("ROLE_USER=" + c);
}
Vikdor
  • 23,934
  • 10
  • 61
  • 84
Joey Jarin
  • 101
  • 1
  • 2
8

You can get some help from AuthorityUtils class. Checking role as a one-liner:

if (AuthorityUtils.authorityListToSet(SecurityContextHolder.getContext().getAuthentication().getAuthorities()).contains("ROLE_MANAGER")) {
    /* ... */
}

Caveat: This does not check role hierarchy, if such exists.

holmis83
  • 15,922
  • 5
  • 82
  • 83
  • That's the simplest solution cause I need to check the List several times and fetching it once with some _magic_ simple routine is great! – LeO Nov 07 '18 at 09:48
7

Most answers are missing some points:

  1. Role and authority are not the same thing in Spring. See here for more details.

  2. Role names are equal to rolePrefix + authority.

  3. The default role prefix is ROLE_, however, it is configurable. See here.

Therefore, a proper role check needs to respect the role prefix if it is configured.

Unfortunately, the role prefix customization in Spring is a bit hacky, in many places the default prefix, ROLE_ is hardcoded, but in addition to that, a bean of type GrantedAuthorityDefaults is checked in the Spring context, and if it exists, the custom role prefix it has is respected.

Bringing all this information together, a better role checker implementation would be something like:

@Component
public class RoleChecker {

    @Autowired(required = false)
    private GrantedAuthorityDefaults grantedAuthorityDefaults;

    public boolean hasRole(String role) {
        String rolePrefix = grantedAuthorityDefaults != null ? grantedAuthorityDefaults.getRolePrefix() : "ROLE_";
        return Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
                .map(Authentication::getAuthorities)
                .map(Collection::stream)
                .orElse(Stream.empty())
                .map(GrantedAuthority::getAuthority)
                .map(authority -> rolePrefix + authority)
                .anyMatch(role::equals);
    }
}
Utku Özdemir
  • 7,390
  • 2
  • 52
  • 49
6

The answer from JoseK can't be used when your in your service layer, where you don't want to introduce a coupling with the web layer from the reference to the HTTP request. If you're looking into resolving the roles while in the service layer, Gopi's answer is the way to go.

However, it's a bit long winded. The authorities can be accessed right from the Authentication. Hence, if you can assume that you have a user logged in, the following does it:

/**
 * @return true if the user has one of the specified roles.
 */
protected boolean hasRole(String[] roles) {
    boolean result = false;
    for (GrantedAuthority authority : SecurityContextHolder.getContext().getAuthentication().getAuthorities()) {
        String userRole = authority.getAuthority();
        for (String role : roles) {
            if (role.equals(userRole)) {
                result = true;
                break;
            }
        }

        if (result) {
            break;
        }
    }

    return result;
}
Starman
  • 426
  • 3
  • 6
6

This two annotation below is equal, "hasRole" will auto add prefix "ROLE_". Make sure you have the right annotation. This role is set in UserDetailsService#loadUserByUsername.

@PreAuthorize("hasAuthority('ROLE_user')")
@PreAuthorize("hasRole('user')")

then, you can get the role in java code.

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(authentication.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_user"))){
    System.out.println("user role2");
}
Luke Cheung
  • 479
  • 6
  • 8
4

This is sort of coming at the question from the other end but I thought I'd throw it in as I really had to dig on the internet to find this out.

There is a lot of stuff about how to check roles but not much saying what you are actually checking when you say hasRole("blah")

HasRole checks the granted authorities for the currently authenticated principal

So really when you see hasRole("blah") really means hasAuthority("blah").

In the case I've seen, you do this with a class that Implements UserDetails which defines a method called getAuthorities. In this you'll basically add some new SimpleGrantedAuthority("some name") to a list based on some logic. The names in this list are the things checked by the hasRole statements.

I guess in this context the UserDetails object is the currently authenticated principal. There's some magic that happens in and around authentication providers and more specifically the authentication-manager that makes this happen.

JonnyRaa
  • 7,559
  • 6
  • 45
  • 49
  • 2
    As of Spring Security 4.0 this `hasRole("bla")` is now equal to `hasAuthority("ROLE_bla")`. – lanoxx Jul 28 '16 at 13:38
3

Strangely enough, I don't think there is a standard solution to this problem, as the spring-security access control is expression based, not java-based. you might check the source code for DefaultMethodSecurityExpressionHandler to see if you can re-use something they are doing there

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
  • So your solution is to use DefaultMethodSecurityExpressionHandler as bean and get expression parser and check it in EL ? – Piotr Gwiazda Jun 11 '10 at 12:03
  • that probably won't work, as the handler operates on methodinvocations (which you don't have in your context). you probably need to create your own bean that does something similar, but without using a methodinvocation context – Sean Patrick Floyd Jun 11 '10 at 12:54
3

In our project, we are using a role hierarchy, while most of the above answers only aim at checking for a specific role, i.e. would only check for the role given, but not for that role and up the hierarchy.

A solution for this:

@Component
public class SpringRoleEvaluator {

@Resource(name="roleHierarchy")
private RoleHierarchy roleHierarchy;

public boolean hasRole(String role) {
    UserDetails dt = AuthenticationUtils.getSessionUserDetails();

    for (GrantedAuthority auth: roleHierarchy.getReachableGrantedAuthorities(dt.getAuthorities())) {
        if (auth.toString().equals("ROLE_"+role)) {
            return true;
        }
    }
    return false;
}

RoleHierarchy is defined as a bean in spring-security.xml.

Kirinya
  • 245
  • 3
  • 12
  • 1
    Or you can populate your roles properly: https://github.com/spring-projects/spring-security/issues/2152#issuecomment-180599279 – arctica Aug 04 '17 at 12:05
2

The @gouki answer is best!

Just a tip of how spring really do this.

There is a class named SecurityContextHolderAwareRequestWrapper which implements the ServletRequestWrapper class.

The SecurityContextHolderAwareRequestWrapper overrides the isUserInRole and search user Authentication (which is managed by Spring) to find if user has a role or not.

SecurityContextHolderAwareRequestWrapper the code is as:

    @Override
    public boolean isUserInRole(String role) {
        return isGranted(role);
    }

 private boolean isGranted(String role) {
        Authentication auth = getAuthentication();

        if( rolePrefix != null ) {
            role = rolePrefix + role;
        }

        if ((auth == null) || (auth.getPrincipal() == null)) {
            return false;
        }

        Collection<? extends GrantedAuthority> authorities = auth.getAuthorities();

        if (authorities == null) {
            return false;
        }

        //This is the loop which do actual search
        for (GrantedAuthority grantedAuthority : authorities) {
            if (role.equals(grantedAuthority.getAuthority())) {
                return true;
            }
        }

        return false;
    }
Alireza Fattahi
  • 42,517
  • 14
  • 123
  • 173
2

Better late then never, let me put in my 2 cents worth.

In JSF world, within my managed bean, I did the following:


HttpServletRequest req = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
SecurityContextHolderAwareRequestWrapper sc = new SecurityContextHolderAwareRequestWrapper(req, "");

As mentioned above, my understanding is that it can be done the long winded way as followed:


Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserDetails userDetails = null;
if (principal instanceof UserDetails) {
    userDetails = (UserDetails) principal;
    Collection  authorities = userDetails.getAuthorities();
}
lukec
  • 21
  • 1
2

User Roles can be checked using following ways:

  1. Using call static methods in SecurityContextHolder:

    Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null && auth.getAuthorities().stream().anyMatch(role -> role.getAuthority().equals("ROLE_NAME"))) { //do something}

  2. Using HttpServletRequest

@GetMapping("/users")
public String getUsers(HttpServletRequest request) {
    if (request.isUserInRole("ROLE_NAME")) {
      
    }
Lucky
  • 575
  • 3
  • 18
1

On your user model just add a 'hasRole' method like below

public boolean hasRole(String auth) {
    for (Role role : roles) {
        if (role.getName().equals(auth)) { return true; }
    }
    return false;
}

I usually use it to check if the authenticated user has the role admin as follows

Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); // This gets the authentication
User authUser = (User) authentication.getPrincipal(); // This gets the logged in user
authUser.hasRole("ROLE_ADMIN") // This returns true or false
0

My Approach with the help of Java8 , Passing coma separated roles will give you true or false

    public static Boolean hasAnyPermission(String permissions){
    Boolean result = false;
    if(permissions != null && !permissions.isEmpty()){
        String[] rolesArray = permissions.split(",");
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        for (String role : rolesArray) {
            boolean hasUserRole = authentication.getAuthorities().stream().anyMatch(r -> r.getAuthority().equals(role));
            if (hasUserRole) {
                result = true;
                break;
            }
        }
    }
    return result;
}
Jajikanth pydimarla
  • 1,512
  • 13
  • 11
0

You can use the annotation @Secured or @RolesAllowed or @PreAuthorise / @PostAuthorise in Spring Security.

Remember: You need to add this code

@Configuration
@EnableGlobalMethodSecurity(
    securedEnabled = true, 
    jsr250Enabled = true, 
    prePostEnabled = true
)
public class MyConfig extends WebSecurityConfigurerAdapter{
}

in front of your configure class. You do not need use all of the 3 parameters securedEnabled, jsr250Enabled, prePostEnabled. You only need one depending on which annotation you want to use.

Then put the role check annotation in your controller class.

@Secured("ROLE_admin")
@GetMapping("/hello")
public String hello(){
    return "hello";
}

or

@RolesAllowed("ROLE_admin")
@GetMapping("/hello")
public String hello(){
    return "hello";
}

or

@PreAuthorize("hasRole('ROLE_user')")
@GetMapping("/hello")
public String hello(){
    return "hello";
}

Here is a tutorial https://www.baeldung.com/spring-security-method-security

Songtao Lou
  • 41
  • 11
-1
public static Boolean isUserInRole(String role) {
    return Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication())
            .map(x->x.getAuthorities())
            .orElse(Collections.emptyList())
            .stream()
            .anyMatch(x->x.getAuthority()
                    .equals(role));
            
}

ChatGPT explanation step by step:

  1. SecurityContextHolder.getContext().getAuthentication(): This retrieves the Authentication object from the SecurityContextHolder. The Authentication object represents the currently authenticated user.

  2. Optional.ofNullable(...): Wraps the Authentication object in an Optional. If the Authentication object is not null, it will be wrapped in an Optional. Otherwise, an empty Optional will be created.

  3. .map(x -> x.getAuthorities()): If the Optional is not empty, this maps the Authentication object to its authorities. The getAuthorities() method retrieves the collection of granted authorities for the user.

  4. .orElse(Collections.emptyList()): If the Optional is empty (i.e., the Authentication object is null or has no authorities), this specifies a default value to use, which is an empty list (Collections.emptyList()). This is done to handle the case when getAuthorities() returns null.

  5. .stream(): Converts the list of authorities to a stream, enabling us to perform stream operations on the elements.

  6. .anyMatch(x -> x.getAuthority().equals(role)): Checks if any of the authorities in the stream match the specified role. The lambda expression x -> x.getAuthority().equals(role) is used to compare each authority's getAuthority() value with the given role. If a match is found, it will return true; otherwise, it will return false.

So, the entire code checks if the current user, obtained from SecurityContextHolder, has an authority matching the specified role. It handles the cases where the user is not authenticated (null Authentication object) or has no authorities, returning false in those cases.