Unterschied zwischen Rolle und GrantedAuthority in Spring Security

226

In Spring Security gibt es Konzepte und Implementierungen, z. B. die GrantedAuthoritySchnittstelle, über die eine Berechtigung zum Autorisieren / Steuern eines Zugriffs erteilt wird .

Ich möchte, dass dies zulässige Vorgänge wie createSubUsers oder deleteAccounts sind , die ich einem Administrator (mit Rolle ROLE_ADMIN) erlauben würde .

Ich bin verwirrt über die Tutorials / Demos, die ich online sehe. Ich versuche zu verbinden, was ich lese, aber ich denke, wir behandeln die beiden austauschbar.

Ich sehe hasRoleeinen GrantedAuthorityString verbrauchen ? Ich mache es definitiv falsch im Verständnis. Was sind diese konzeptionell in Spring Security?

Wie speichere ich die Rolle eines Benutzers getrennt von den Behörden für diese Rolle?

Ich schaue mir auch die org.springframework.security.core.userdetails.UserDetailsSchnittstelle an, die in dem DAO verwendet wird, auf das der Authentifizierungsanbieter verweist und das a verbraucht User(siehe letzte GrantedAuthority):

public User(String username, 
            String password, 
            boolean enabled, 
            boolean accountNonExpired,
            boolean credentialsNonExpired, 
            boolean accountNonLocked, 
            Collection<? extends GrantedAuthority> authorities)

Oder gibt es eine andere Möglichkeit, die beiden anderen zu unterscheiden? Oder wird es nicht unterstützt und wir müssen unser eigenes machen?

Chinmay
quelle

Antworten:

365

Stellen Sie sich eine GrantedAuthority als "Erlaubnis" oder "Recht" vor. Diese "Berechtigungen" werden (normalerweise) als Zeichenfolgen (mit der getAuthority()Methode) ausgedrückt . Mit diesen Zeichenfolgen können Sie die Berechtigungen identifizieren und Ihre Wähler entscheiden, ob sie Zugriff auf etwas gewähren.

Sie können Benutzern verschiedene GrantedAuthoritys (Berechtigungen) erteilen, indem Sie sie in den Sicherheitskontext stellen. Normalerweise implementieren Sie dazu Ihren eigenen UserDetailsService, der eine UserDetails-Implementierung zurückgibt, die die erforderlichen GrantedAuthorities zurückgibt.

Rollen (wie sie in vielen Beispielen verwendet werden) sind nur "Berechtigungen" mit einer Namenskonvention, die besagt, dass eine Rolle eine GrantedAuthority ist, die mit dem Präfix beginnt ROLE_. Mehr gibt es nicht. Eine Rolle ist nur eine GrantedAuthority - eine "Erlaubnis" - ein "Recht". In der Frühlingssicherheit sehen Sie viele Stellen, an denen die Rolle mit ihrem ROLE_Präfix speziell behandelt wird, z. B. im RoleVoter, wo das ROLE_Präfix standardmäßig verwendet wird. Auf diese Weise können Sie die Rollennamen ohne ROLE_Präfix angeben . Vor Spring Security 4 wurde dieser spezielle Umgang mit "Rollen" nicht sehr konsequent befolgt, und Behörden und Rollen wurden häufig gleich behandelt (wie Sie zhasAuthority()hasRole()). Mit Spring Security 4 ist die Behandlung von Rollen konsistenter und Code, der sich mit "Rollen" (wie dem RoleVoter, dem hasRoleAusdruck usw.) befasst, fügt immer das ROLE_Präfix für Sie hinzu. Bedeutet hasAuthority('ROLE_ADMIN')also dasselbe wie hasRole('ADMIN')weil das ROLE_Präfix automatisch hinzugefügt wird. Weitere Informationen finden Sie im Migrationshandbuch für Federsicherheit 3 bis 4 .

Aber dennoch: Eine Rolle ist nur eine Autorität mit einem speziellen ROLE_Präfix. In Spring ist Sicherheit 3 @PreAuthorize("hasRole('ROLE_XYZ')")dasselbe wie @PreAuthorize("hasAuthority('ROLE_XYZ')")und in Spring ist Sicherheit 4 @PreAuthorize("hasRole('XYZ')")dasselbe wie @PreAuthorize("hasAuthority('ROLE_XYZ')").

In Bezug auf Ihren Anwendungsfall:

Benutzer haben Rollen und Rollen können bestimmte Vorgänge ausführen.

Sie könnten sich GrantedAuthoritiesfür die Rollen entscheiden, zu denen ein Benutzer gehört, und für die Vorgänge, die eine Rolle ausführen kann. Die GrantedAuthoritiesfür die Rollen haben das Präfix ROLE_und die Operationen haben das Präfix OP_. Ein Beispiel für Behörden Betrieb könnte sein OP_DELETE_ACCOUNT, OP_CREATE_USER, OP_RUN_BATCH_JOBusw. können Rollen sein ROLE_ADMIN, ROLE_USER, ROLE_OWNERusw.

Möglicherweise werden Ihre Entitäten GrantedAuthoritywie in diesem Beispiel (Pseudocode) implementiert :

@Entity
class Role implements GrantedAuthority {
    @Id
    private String id;

    @ManyToMany
    private final List<Operation> allowedOperations = new ArrayList<>();

    @Override
    public String getAuthority() {
        return id;
    }

    public Collection<GrantedAuthority> getAllowedOperations() {
        return allowedOperations;
    }
}

@Entity
class User {
    @Id
    private String id;

    @ManyToMany
    private final List<Role> roles = new ArrayList<>();

    public Collection<Role> getRoles() {
        return roles;
    }
}

@Entity
class Operation implements GrantedAuthority {
    @Id
    private String id;

    @Override
    public String getAuthority() {
        return id;
    }
}

Die IDs der Rollen und Operationen , die Sie in Ihrer Datenbank erstellen würde die GrantedAuthority Darstellung, zB ROLE_ADMIN, OP_DELETE_ACCOUNTusw. Wenn ein Benutzer authentifiziert wird, stellen Sie sicher , dass alle GrantedAuthorities aller seiner Rollen und die entsprechenden Operationen werden von den UserDetails.getAuthorities () zurück Methode.

Beispiel: Die Admin - Rolle mit der ID ROLE_ADMINhat die Operationen OP_DELETE_ACCOUNT, OP_READ_ACCOUNT, OP_RUN_BATCH_JOBihm zugeordneten. Die Benutzerrolle mit ID ROLE_USERhat die Operation OP_READ_ACCOUNT.

Wenn ein Admin - Protokolle in der resultierenden Sicherheitskontext werden die GrantedAuthorities haben: ROLE_ADMIN, OP_DELETE_ACCOUNT, OP_READ_ACCOUNT,OP_RUN_BATCH_JOB

Wenn ein Benutzer meldet es, wird es: ROLE_USER,OP_READ_ACCOUNT

Der UserDetailsService würde dafür sorgen, dass alle Rollen und alle Operationen dieser Rollen erfasst und durch die Methode getAuthorities () in der zurückgegebenen UserDetails-Instanz verfügbar gemacht werden.

James
quelle
2
Danke dir! Ich habe überall gesucht, warum "hasRole ('rolename')" in Spring 4 nicht funktioniert hat -> Ihre Dokumentation war nicht gerade schnell zu überfliegen. Nur ein kurzes "Finden und Ersetzen" und ich bin wieder auf dem richtigen Weg!
Jørgen Skår Fischer
12
Dies ist eine großartige Antwort. Eine Sache, die klargestellt werden muss, um sie etwas anders zu erklären: hasRole('xyz')In Spring Security 4 wird erwartet, dass Sie das Präfix ROLE_ haben, während das Präfix hasAuthority('xyz')nicht erwartet und genau bewertet, was übergeben wird. Ich habe diese Lösung verwendet, bin aber hasRole('OP_MY_PERMISSION')seitdem auf Probleme gestoßen der ROLE_ Präfix benötigt wurde. Stattdessen hätte ich das verwenden sollen, hasAuthority('OP_MY_PERMISSION')da ich das Präfix nicht hatte.
Randal4
@ James können Sie sich diese Frage ansehen stackoverflow.com/questions/41500031/…
saurabh kumar
1
In JSTL ist springframework.org/security/tags <sec:authorize access="hasRole('ADMIN')">dasselbe wie<sec:authorize access="hasRole('ROLE_ADMIN')">
Alex78191
1
Ja. OP_ ist nur ein beliebiges Präfix. ROLE_ hat in einigen Federimplementierungen eine besondere Bedeutung.
James
9

AFAIK GrantedAuthority und Rollen sind in der Frühlingssicherheit gleich. Die getAuthority () - Zeichenfolge von GrantedAuthority ist die Rolle (gemäß Standardimplementierung SimpleGrantedAuthority).

Für Ihren Fall können Sie hierarchische Rollen verwenden

<bean id="roleVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">
    <constructor-arg ref="roleHierarchy" />
</bean>
<bean id="roleHierarchy"
        class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
    <property name="hierarchy">
        <value>
            ROLE_ADMIN > ROLE_createSubUsers
            ROLE_ADMIN > ROLE_deleteAccounts 
            ROLE_USER > ROLE_viewAccounts
        </value>
    </property>
</bean>

Nicht das genaue Sol, das Sie suchen, aber ich hoffe, es hilft

Bearbeiten : Auf Ihren Kommentar antworten

Rolle ist wie eine Erlaubnis in der Frühlingssicherheit. Die Verwendung von Intercept-URL mit hasRole bietet eine sehr genaue Kontrolle darüber, welche Operation für welche Rolle / Berechtigung zulässig ist.

In unserer Anwendung definieren wir die Berechtigung (dh die Rolle) für jede Operation (oder Ruhe-URL) für z. B. view_account, delete_account, add_account usw. Anschließend erstellen wir logische Profile für jeden Benutzer wie admin, guest_user, normal_user. Die Profile sind nur logische Gruppierungen von Berechtigungen, unabhängig von der Federsicherheit. Wenn ein neuer Benutzer hinzugefügt wird, wird ihm ein Profil zugewiesen (mit allen zulässigen Berechtigungen). Wenn ein Benutzer versucht, eine Aktion auszuführen, wird die Berechtigung / Rolle für diese Aktion mit den vom Benutzer gewährten Berechtigungen verglichen.

Außerdem verwendet der Standard-RoleVoter das Präfix ROLE_, sodass jede Berechtigung, die mit ROLE_ beginnt, als Rolle betrachtet wird. Sie können dieses Standardverhalten ändern, indem Sie ein benutzerdefiniertes RolePrefix im Rollenwähler verwenden und es in der Frühlingssicherheit verwenden.

Codierer
quelle
1
Danke für Ihre Hilfe. Hierarchie scheint etwas anderes zu sein. Die Art und Weise, wie ich es jetzt mache (wenn ich Spring Security verwenden muss), besteht darin, sowohl die Rolle als auch die Berechtigung in derselben Liste zu speichern und das Prädikat hasRole zu verwenden, um die Überprüfungen für beide durchzuführen. Denken Sie mehr darüber nach - dies wird wahrscheinlich von den Jungs von Spring Security beabsichtigt? Gibt es eine andere Möglichkeit, die Intercept-URL als die Überprüfung mit hasRole in der vollständigen Liste der Rollen UND Berechtigungen / Berechtigungen - oder anderer Berechtigungsanwendungen - zu verwenden? Was ist auch die Notwendigkeit, ROLE_ voranzustellen? Ist es Konvention?
Chinmay
7

Eine andere Möglichkeit, die Beziehung zwischen diesen Konzepten zu verstehen, besteht darin, eine ROLLE als Container von Behörden zu interpretieren.

Behörden sind detaillierte Berechtigungen, die auf eine bestimmte Aktion abzielen, manchmal verbunden mit einem bestimmten Datenumfang oder Kontext. Beispielsweise kann Lesen, Schreiben, Verwalten verschiedene Berechtigungsstufen für einen bestimmten Informationsbereich darstellen.

Außerdem werden die Behörden tief im Verarbeitungsablauf einer Anforderung durchgesetzt, während die ROLLE nach dem Anforderungsfilter gefiltert wird, bevor sie den Controller erreichen. Best Practices schreiben die Implementierung der behördlichen Durchsetzung hinter dem Controller in der Geschäftsschicht vor.

Andererseits sind ROLES eine grobkörnige Darstellung einer Reihe von Berechtigungen. Ein ROLE_READER hätte nur Lese- oder Anzeigeberechtigung, während ein ROLE_EDITOR sowohl Lese- als auch Schreibberechtigung hätte. Rollen werden hauptsächlich für ein erstes Screening am Rande der Anforderungsverarbeitung verwendet, z. B. http. ... .antMatcher (...). hasRole (ROLE_MANAGER)

Die Behörden, die tief im Prozessablauf der Anforderung durchgesetzt werden, ermöglichen eine feinkörnigere Anwendung der Berechtigung. Beispielsweise kann ein Benutzer über die Berechtigung zum Lesen und Schreiben verfügen, um eine Ressource auf der ersten Ebene zu speichern, jedoch nur zum Lesen in eine Unterressource. Ein ROLE_READER würde sein Recht einschränken, die Ressource der ersten Ebene zu bearbeiten, da er die Schreibberechtigung zum Bearbeiten dieser Ressource benötigt, aber ein @ PreAuthorize-Interceptor könnte seinen Versuch blockieren, die Unterressource zu bearbeiten.

Jake

Softjake
quelle
2

Wie andere bereits erwähnt haben, stelle ich mir Rollen als Container für detailliertere Berechtigungen vor.

Obwohl ich festgestellt habe, dass die Implementierung der Hierarchierolle keine genaue Kontrolle über diese detaillierten Berechtigungen hat.
Deshalb habe ich eine Bibliothek erstellt, um die Beziehungen zu verwalten und die Berechtigungen als erteilte Berechtigungen in den Sicherheitskontext einzufügen.

Möglicherweise verfügt die App über eine Reihe von Berechtigungen, z. B. CREATE, READ, UPDATE, DELETE, die dann der Rolle des Benutzers zugeordnet sind.

Oder spezifischere Berechtigungen wie READ_POST, READ_PUBLISHED_POST, CREATE_POST, PUBLISH_POST

Diese Berechtigungen sind relativ statisch, aber die Beziehung der Rollen zu ihnen kann dynamisch sein.

Beispiel -

@Autowired 
RolePermissionsRepository repository;

public void setup(){
  String roleName = "ROLE_ADMIN";
  List<String> permissions = new ArrayList<String>();
  permissions.add("CREATE");
  permissions.add("READ");
  permissions.add("UPDATE");
  permissions.add("DELETE");
  repository.save(new RolePermissions(roleName, permissions));
}

Sie können APIs erstellen, um die Beziehung dieser Berechtigungen zu einer Rolle zu verwalten.

Ich möchte keine weitere Antwort kopieren / einfügen. Hier ist der Link zu einer vollständigeren Erklärung zu SO.
https://stackoverflow.com/a/60251931/1308685

Um meine Implementierung wiederzuverwenden, habe ich ein Repo erstellt. Bitte zögern Sie nicht, einen Beitrag zu leisten!
https://github.com/savantly-net/spring-role-permissions

Jeremy
quelle