Comment vérifier "hasRole" dans le Code Java avec Spring Security?
Comment vérifier l'autorité ou l'autorisation de l'utilisateur dans le Code Java ? Par exemple je veux afficher ou masquer le bouton pour l'utilisateur en fonction du 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"));
}
16 réponses
Spring Security 3.0 a cette API
SecurityContextHolderAwareRequestWrapper.isUserInRole(String role)
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
}
}
Au Lieu d'utiliser une boucle pour trouver l'autorité de UserDetails vous pouvez faire:
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
boolean authorized = authorities.contains(new SimpleGrantedAuthority("ROLE_ADMIN"));
Vous pouvez récupérer le contexte de sécurité, puis l'utiliser:
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;
}
Vous pouvez implémenter une méthode hasRole () comme ci - dessous - (Ceci est testé sur spring security 3.0.x Pas sûr 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;
}
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);
}
La réponse de JoseK ne peut pas être utilisée lorsque vous êtes dans votre couche de service, où vous ne voulez pas introduire un couplage avec la couche web à partir de la référence à la requête HTTP. Si vous envisagez de résoudre les rôles dans la couche de service, la réponse de Gopi est la voie à suivre.
Cependant, il est un peu longue haleine. Les autorités sont accessibles directement à partir de L'authentification. Par conséquent, si vous pouvez supposer que vous avez un utilisateur connecté, ce qui suit le fait:
/**
* @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;
}
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, pas basé sur java. vous pouvez vérifier le code source de DefaultMethodSecurityExpressionHandler pour voir si vous pouvez réutiliser quelque chose qu'ils font là
Mieux vaut tard que jamais, laissez-moi mettre mes 2 cents de valeur.
Dans JSF world, 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 de la manière longue comme suit:
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserDetails userDetails = null;
if (principal instanceof UserDetails) {
userDetails = (UserDetails) principal;
Collection authorities = userDetails.getAuthorities();
}
Cela vient en quelque sorte à la question de l'autre bout, mais je pensais que je le jetterais car je devais vraiment creuser sur internet pour le savoir.
Il y a beaucoup de choses sur la façon de vérifier les rôles, mais pas beaucoup dire ce que vous vérifiez réellement quand vous dites hasRole ("blah")
HasRole vérifie les autorisations accordées pour le principal authentifié
Alors, vraiment, quand vous voyez hasRole("bla") signifie vraiment hasAuthority("bla").
Dans le cas que j'ai vu, vous le faites avec une classe qui implémente UserDetails qui définit une méthode appelée getAuthorities. En cela, vous allez essentiellement Ajouter new SimpleGrantedAuthority("some name")
à une liste basée sur une logique. Les noms dans cette liste sont les choses vérifiées par les instructions hasRole.
Je suppose que dans ce contexte, L'objet UserDetails est le principal actuellement authentifié. Il y a une certaine magie qui se produit dans et autour des fournisseurs d'authentification et plus encore plus précisément, le gestionnaire d'authentification qui rend cela possible.
La réponse @ gouki est la meilleure!
Juste un conseil de la façon dont le printemps fait vraiment cela.
Il existe une classe nommée SecurityContextHolderAwareRequestWrapper
qui implémente la classe ServletRequestWrapper
.
Le SecurityContextHolderAwareRequestWrapper
remplace le isUserInRole
et recherche Utilisateur Authentication
(qui est géré par Spring) pour trouver si l'Utilisateur a un rôle ou non.
SecurityContextHolderAwareRequestWrapper
le code est:
@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;
}
Vous pouvez obtenir de l'aide de la classe AuthorityUtils. Vérification du rôle en tant que One-liner:
if (AuthorityUtils.authorityListToSet(SecurityContextHolder.getContext().getAuthentication().getAuthorities()).contains("ROLE_MANAGER")) {
/* ... */
}
Mise en garde: cela ne vérifie pas la hiérarchie des rôles, si elle existe.
La plupart des réponses manquent quelques points:
Rôle et l'autorité ne sont pas la même chose au Printemps. Voir ici pour plus détails.
Les noms de rôles sont égales à
rolePrefix
+authority
.Le préfixe de rôle par défaut est
ROLE_
, cependant, 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 de rôle dans Spring est un peu hacky, dans de nombreux endroits, le préfixe par défaut, ROLE_
est codé en dur, mais en plus de cela, un bean de type GrantedAuthorityDefaults
est vérifié dans le contexte Spring, et s'il existe, le préfixe de rôle personnalisé qu'il a est respecté.
En rassemblant toutes ces informations, une meilleure implémentation du vérificateur de rôles serait 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);
}
}
Dans notre projet, nous utilisons une hiérarchie de rôles, alors que la plupart des réponses ci-dessus ne visent qu'à vérifier un rôle spécifique, c'est-à-dire ne vérifieraient que le rôle donné, mais pas ce rôle et la hiérarchie.
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.
Mon approche avec L'aide de Java8, en passant des rôles séparés par coma vous donnera true ou 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;
}
Pour vérifier le rôle de l'utilisateur, vous pouvez essayer ceci:
public static boolean isCurrentUserInRole(String authority) {
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
if (authentication != null) {
return authentication.getAuthorities().stream()
.anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(authority));
}
return false;
}
Puis :
if(SecurityUtils.isCurrentUserInRole(AuthoritiesConstants.ADMIN))
{
`enter code here`
}