web-dev-qa-db-fra.com

Comment vérifier "hasRole" dans le code Java avec Spring Security?

Comment vérifier les droits d'utilisateur ou les autorisations dans Java Code? Par exemple, je souhaite afficher ou masquer un bouton pour un utilisateur en fonction de son rôle. Il y a des annotations comme:

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

Comment le faire en code Java? Quelque chose comme : 

if(somethingHere.hasRole("ROLE_MANAGER")) {
   layout.addComponent(new Button("Edit users"));
}
105
Piotr Gwiazda

Spring Security 3.0 a cette API 

SecurityContextHolderAwareRequestWrapper.isUserInRole(String role)

Vous devrez injecter l'emballage avant de l'utiliser.

SecurityContextHolderAwareRequestWrapper

68
JoseK

vous pouvez utiliser la méthode isUserInRole de l'objet HttpServletRequest.

quelque chose comme:

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


    if (request.isUserInRole("ROLE_ADMIN")) {
        // code here
    }
}
128
gouki

Au lieu d'utiliser une boucle pour rechercher l'autorité à partir de UserDetails, vous pouvez effectuer les tâches suivantes:

Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
boolean authorized = authorities.contains(new SimpleGrantedAuthority("ROLE_ADMIN"));
59
Ninca

Vous pouvez récupérer le contexte de sécurité puis utiliser celui-ci:

    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;
    }
44
Nate Sammons

Vous pouvez implémenter une méthode hasRole () comme ci-dessous - (Ceci est testé sur spring security 3.0.x pas certain des autres 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;
  }
13
Gopi

J'utilise ceci:

@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);
}
9
Joey Jarin

La réponse de JoseK ne peut pas être utilisée lorsque vous êtes dans votre couche de services, où vous ne souhaitez pas introduire de couplage avec la couche Web depuis la référence à la requête HTTP. Si vous envisagez de résoudre les rôles dans la couche service, la réponse de Gopi est la solution.

Cependant, c'est un peu long. Les autorités sont accessibles directement à partir de l'authentification. Par conséquent, si vous pouvez supposer qu'un utilisateur est connecté, procédez comme suit:

/**
 * @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;
}
5
Starman

Vous pouvez obtenir de l'aide de AuthorityUtils class. Vérification du rôle en une ligne:

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

Avertissement: cela ne vérifie pas la hiérarchie des rôles, s'il en existe une.

4
holmis83

Curieusement, je ne pense pas qu'il existe une solution standard à ce problème, car le contrôle d'accès Spring-Security est basé sur l'expression , et non sur Java. vous pouvez vérifier le code source pour DefaultMethodSecurityExpressionHandler pour voir si vous pouvez réutiliser quelque chose qu'ils font là

2
Sean Patrick Floyd

La réponse @gouki est la meilleure! 

Juste une pointe de comment le printemps fait vraiment cela. 

Il existe une classe nommée SecurityContextHolderAwareRequestWrapper qui implémente la classe ServletRequestWrapper

La SecurityContextHolderAwareRequestWrapper remplace la isUserInRole et recherche l'utilisateur Authentication (qui est géré par Spring) pour rechercher si l'utilisateur a un rôle ou non.

SecurityContextHolderAwareRequestWrapper le code est le suivant:

    @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;
    }
2
Alireza Fattahi

Mieux vaut tard que jamais, laissez-moi mettre mes 2 cents.

Dans le monde JSF, dans mon bean géré, j'ai fait ce qui suit:


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

Comme mentionné ci-dessus, ma compréhension est que cela peut être fait à la longue comme suit:


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

La plupart des réponses manquent quelques points: 

  1. Le rôle et l'autorité ne sont pas la même chose au printemps. Voir ici pour plus détails.

  2. Les noms de rôle sont égaux à rolePrefix + authority.

  3. Le préfixe de rôle par défaut est ROLE_; toutefois, il est configurable. Voir ici .

Par conséquent, une vérification de rôle appropriée doit respecter le préfixe de rôle s'il est configuré. 

Malheureusement, la personnalisation du préfixe du rôle dans Spring est un peu compliquée. À plusieurs endroits, le préfixe par défaut, ROLE_, est codé en dur, mais en plus de cela, un bean de type GrantedAuthorityDefaults est coché dans le contexte Spring, et s'il existe, le rôle personnalisé le préfixe qu'il a est respecté.

En rassemblant toutes ces informations, une meilleure implémentation du vérificateur de rôle ressemblerait à quelque chose comme:

@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);
    }
}
2
Utku Özdemir

Cela vient en quelque sorte de la question de l’autre bout, mais j’ai pensé que j’en ferais autant car je devais vraiment creuser sur Internet pour le découvrir.

Il y a beaucoup de choses sur la façon de vérifier les rôles mais pas beaucoup de dire ce que vous vérifiez réellement quand vous dites hasRole ("blah")

HasRole vérifie les autorisations accordées pour le principal actuellement authentifié

Donc, vraiment, lorsque vous voyez hasRole ("blah") signifie vraiment hasAuthority ("blah") .

Dans le cas que j'ai vu, vous le faites avec une classe implémentant UserDetails, qui définit une méthode appelée getAuthorities. En cela, vous ajouterez fondamentalement new SimpleGrantedAuthority("some name") à une liste basée sur une logique. Les noms dans cette liste sont les éléments vérifiés par les instructions hasRole.

J'imagine que dans ce contexte, l'objet UserDetails est le principal actuellement authentifié. Il existe une certaine magie dans et autour des fournisseurs d'authentification et plus particulièrement du gestionnaire d'authentification qui rend cela possible.

1
JonnyRaa

Sur votre modèle utilisateur, ajoutez simplement une méthode 'hasRole' comme ci-dessous

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

Je l'utilise généralement pour vérifier si l'utilisateur authentifié a le rôle admin comme suit

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
user8174892

Les deux annotations ci-dessous sont égales, "hasRole" ajoutera automatiquement le préfixe "ROLE_". Assurez-vous d'avoir la bonne annotation. Ce rôle est défini dans UserDetailsService # loadUserByUsername.

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

alors, vous pouvez obtenir le rôle en code Java.

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

Mon approche à l'aide de Java 8, le fait de passer des rôles séparés par des virgules vous donnera un résultat vrai ou faux

    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;
}
0

Dans notre projet, nous utilisons une hiérarchie des rôles, alors que la plupart des réponses ci-dessus visent uniquement à vérifier un rôle spécifique, c’est-à-dire qu’elles ne vérifient que le rôle attribué, mais pas ce rôle et la hiérarchie supérieure.

Une solution pour cela:

@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 est défini comme un bean dans spring-security.xml.

0
Kirinya