Wie überprüfe ich "hasRole" in Java Code mit Spring Security?


118

Wie überprüfe ich die Berechtigung oder Berechtigung des Benutzers in Java Code? Zum Beispiel - Ich möchte die Schaltfläche für den Benutzer je nach Rolle ein- oder ausblenden. Es gibt Anmerkungen wie:

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

Wie mache ich es in Java-Code? Etwas wie :

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

Antworten:


70

Spring Security 3.0 verfügt über diese API

SecurityContextHolderAwareRequestWrapper.isUserInRole(String role)

Sie müssen den Wrapper injizieren, bevor Sie ihn verwenden.

SecurityContextHolderAwareRequestWrapper


53
Wie Ihre Antwort besagt, sieht es so aus, als ob die Methode statisch ist, Sie benötigen jedoch eine SecurityContextHolderAwareRequestWrapperInstanz. Sie können es verbessern, indem Sie erklären, wie Sie es erhalten, und die Antwort selbst ein wenig genauer erläutern.
Xtreme Biker

3
Wie kann ich den Wrapper im Controller abrufen?
Alfonso Tienda

3
Wie kann ich eine Instanz von SecurityContextHolderAwareRequestWrapper erhalten?
gstackoverflow

2
Xtreme Biker hat recht. Wie erhält man die SecurityContextHolderAwareRequestWrapper-Klasse? Es ist kein statisches Objekt.
Probieren Sie es aus

5
Wenn dies eine Web-App wäre, wie es aussieht, können Sie einfach SecurityContextHolderAwareRequestWrapper als Parameter hinzufügen. Und wenn es eine Web-App wäre, könnten Sie einfach HttpServletRequest als Parameter deklarieren und isUserInRole
David Bradley

144

Sie können die isUserInRole-Methode des HttpServletRequest-Objekts verwenden.

etwas wie:

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


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

einfacher zu testen denke ich
fego

1
aber wenn ich nicht angefragt habe?
gstackoverflow

Was ist ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest()mit der Anfrage? :)
Petr Újezdský

4
@Autowired HttpServletRequest-Anforderung; ?
Pascal

Und das ist nicht einmal eine Spring-API, eine einfache Servlet-Spezifikation! Schade, dass das nicht die gewählte Antwort ist
Gregfqt

67

Anstatt eine Schleife zu verwenden, um die Berechtigung aus UserDetails zu ermitteln, können Sie Folgendes tun:

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

2
Eine viel schönere Antwort, jedoch sollte ROLE_ADMIN in doppelten Anführungszeichen stehen.
Erica Kane

6
Das ist sehr riskant. Beachten Sie, dass der Wechsel zu einer anderen Implementierung der GrantedAuthority-Implementierung (z. B. JAAS durch Hinzufügen einer weiteren Autorisierungsmöglichkeit) zu einer Fehlfunktion dieses Codes führt. Siehe equals () Implementierung in SimpleGrantedAuthority
Petr Újezdský

47

Sie können den Sicherheitskontext abrufen und dann Folgendes verwenden:

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

SecurityContextHolder.getContext()ist nie NULL, überprüfen Sie die Dokumente. So können Sie vermeiden, den Kontext zu überprüfen NULL.
Imtiaz Shakil Siddique

14

Sie können eine hasRole () -Methode wie folgt implementieren: (Dies wird unter Spring Security 3.0.x getestet. Bei anderen Versionen sind Sie sich nicht sicher.)

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

1
SecurityContextHolder.getContext().getAuthentication()kann abrufen null. Vielleicht fügst du einen Scheck hinzu?
Mrusful

10

Ich benutze dies:

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

8

Sie können Hilfe von der AuthorityUtils- Klasse erhalten. Überprüfung der Rolle als Einzeiler:

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

Vorsichtsmaßnahme: Hiermit wird die Rollenhierarchie nicht überprüft, sofern eine solche vorhanden ist.


Das ist die einfachste Lösung, da ich die Liste mehrmals überprüfen muss und es großartig ist , sie einmal mit einer magischen einfachen Routine abzurufen!
LeO

6

Die Antwort von JoseK kann nicht verwendet werden, wenn Sie sich in Ihrer Service-Schicht befinden und keine Kopplung mit der Web-Schicht aus dem Verweis auf die HTTP-Anforderung einführen möchten. Wenn Sie die Rollen in der Service-Schicht auflösen möchten, ist Gopis Antwort der richtige Weg.

Es ist jedoch etwas langatmig. Auf die Behörden kann direkt über die Authentifizierung zugegriffen werden. Wenn Sie also davon ausgehen können, dass ein Benutzer angemeldet ist, geschieht Folgendes:

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

6

Den meisten Antworten fehlen einige Punkte:

  1. Rolle und Autorität sind im Frühling nicht dasselbe. Sehen Sie hier für weitere Details.

  2. Rollennamen sind gleich rolePrefix+ authority.

  3. Das Standardrollenpräfix ist ROLE_jedoch konfigurierbar. Siehe hier .

Daher muss bei einer ordnungsgemäßen Rollenprüfung das Rollenpräfix berücksichtigt werden, wenn es konfiguriert ist.

Leider ist die Anpassung des Rollenpräfixes in Spring etwas hackig, an vielen Stellen ist das Standardpräfix fest ROLE_codiert, aber zusätzlich wird eine Bean vom Typ GrantedAuthorityDefaultsim Spring-Kontext überprüft, und falls vorhanden, das benutzerdefinierte Rollenpräfix hat respektiert.

Wenn Sie all diese Informationen zusammenführen, wäre eine bessere Implementierung des Rollenprüfers wie folgt:

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

3

Seltsamerweise glaube ich nicht, dass es eine Standardlösung für dieses Problem gibt, da die Spring-Security-Zugriffskontrolle ausdrucksbasiert und nicht java-basiert ist. Sie können den Quellcode für DefaultMethodSecurityExpressionHandler überprüfen, um festzustellen , ob Sie etwas, das dort ausgeführt wird, wiederverwenden können


Ihre Lösung besteht also darin, DefaultMethodSecurityExpressionHandler als Bean zu verwenden, den Ausdrucksparser abzurufen und in EL zu überprüfen.
Piotr Gwiazda

Das wird wahrscheinlich nicht funktionieren, da der Handler Methodenaufrufe ausführt (die Sie in Ihrem Kontext nicht haben). Sie müssen wahrscheinlich Ihre eigene Bean erstellen, die etwas Ähnliches tut, aber ohne einen Methodeninvokationskontext zu verwenden
Sean Patrick Floyd

2

Besser spät als nie, lass mich meine 2 Cent einbringen.

In der JSF-Welt habe ich in meiner verwalteten Bean Folgendes getan:


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

Wie oben erwähnt, ist mein Verständnis, dass es auf die langwierige Weise wie folgt gemacht werden kann:


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

2

Dies ist eine Art Frage vom anderen Ende, aber ich dachte, ich würde sie einwerfen, da ich wirklich im Internet graben musste, um das herauszufinden.

Es gibt eine Menge Dinge darüber, wie man Rollen überprüft, aber nicht viel darüber, was Sie tatsächlich überprüfen, wenn Sie hasRole ("bla") sagen.

HasRole überprüft die erteilten Berechtigungen auf den aktuell authentifizierten Principal

Wenn Sie also hasRole ("bla") sehen, bedeutet dies wirklich hasAuthority ("bla"). .

In dem Fall, den ich gesehen habe, tun Sie dies mit einer Klasse, die UserDetails implementiert und eine Methode namens getAuthorities definiert. In diesem werden Sie im Grunde einige hinzufügennew SimpleGrantedAuthority("some name") zu einer Liste hinzu, die auf einer Logik basiert. Die Namen in dieser Liste sind die Dinge, die von den hasRole-Anweisungen überprüft werden.

Ich denke in diesem Zusammenhang ist das UserDetails-Objekt der aktuell authentifizierte Principal. Es gibt etwas Magisches in und um Authentifizierungsanbieter und insbesondere den Authentifizierungsmanager, der dies ermöglicht.


2
Ab Spring Security 4.0 ist dies hasRole("bla")jetzt gleich hasAuthority("ROLE_bla").
Lanoxx

2

Die @ gouki Antwort ist am besten!

Nur ein Tipp, wie der Frühling das wirklich macht.

Es gibt eine Klasse namens, die SecurityContextHolderAwareRequestWrapperdas implementiertServletRequestWrapper Klasse .

Das SecurityContextHolderAwareRequestWrapperüberschreibt den isUserInRoleund SuchbenutzerAuthentication (der von Spring verwaltet wird), um festzustellen, ob der Benutzer eine Rolle hat oder nicht.

SecurityContextHolderAwareRequestWrapper Der Code lautet wie folgt:

    @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

Diese beiden Anmerkungen unten sind gleich. "HasRole" fügt automatisch das Präfix "ROLE_" hinzu. Stellen Sie sicher, dass Sie die richtige Anmerkung haben. Diese Rolle wird in UserDetailsService # loadUserByUsername festgelegt.

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

Dann können Sie die Rolle in Java-Code erhalten.

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

1

In unserem Projekt verwenden wir eine Rollenhierarchie, während die meisten der obigen Antworten nur darauf abzielen, nach einer bestimmten Rolle zu suchen, dh nur nach der angegebenen Rolle, aber nicht nach dieser Rolle und nach oben in der Hierarchie.

Eine Lösung dafür:

@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 ist in spring-security.xml als Bean definiert.


1
Oder Sie können Ihre Rollen richtig füllen
arctica

1

Fügen Sie Ihrem Benutzermodell einfach eine 'hasRole'-Methode wie unten hinzu

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

Normalerweise verwende ich es, um zu überprüfen, ob der authentifizierte Benutzer die folgende Rolle als Administrator hat

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

1

Benutzerrollen können auf folgende Arten überprüft werden:

  1. Verwenden statischer Aufrufmethoden in SecurityContextHolder:

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

  2. Verwenden von HttpServletRequest

@GetMapping("/users")
public String getUsers(HttpServletRequest request) {
    if (request.isUserInRole("ROLE_NAME")) {
      
    }


0

Mein Ansatz mit Hilfe von Java8: Wenn Sie durch Koma getrennte Rollen übergeben, erhalten Sie wahr oder falsch

    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;
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.