331 votes

Différence entre le rôle et l'autorité accordée dans Spring Security

Il existe des concepts et des implémentations dans Spring Security, tels que l'interface GrantedAuthority pour obtenir une autorité afin d'autoriser/contrôler un accès.

J'aimerais que des opérations permises, telles que createSubUsers ou deleteAccounts, soient autorisées à un admin (avec le rôle ROLE_ADMIN).

Je suis confus à cause des tutoriels/démos que je vois en ligne. J'essaie de connecter ce que je lis, mais je pense que nous traitons les deux de manière interchangeable.

Je vois que hasRole consomme une chaîne GrantedAuthority

Comment puis-je stocker le rôle d'un utilisateur, séparément des autorités pour ce rôle?

``

Je regarde aussi l'interface org.springframework.security.core.userdetails.UserDetails qui est utilisée dans l'authentification-provider DAO référencée, qui consomme un User (notez la dernière GrantedAuthority):

public User(String username, 
            String password, 
            boolean enabled, 
            boolean accountNonExpired,
            boolean credentialsNonExpired, 
            boolean accountNonLocked, 
            Collection authorities)

Y a-t-il une autre façon de différencier les deux? Ou n'est-ce pas pris en charge et devons-nous créer le nôtre?

``

495voto

James Points 1936

Pensez à une GrantedAuthority comme étant une "autorisation" ou un "droit". Ces "autorisations" sont (normalement) exprimées sous forme de chaînes de caractères (avec la méthode getAuthority()). Ces chaînes vous permettent d'identifier les autorisations et de laisser vos voteurs décider s'ils accordent l'accès à quelque chose.

Vous pouvez accorder différentes GrantedAuthoritys (autorisations) aux utilisateurs en les plaçant dans le contexte de sécurité. Vous le faites normalement en implémentant votre propre UserDetailsService qui renvoie une implémentation de UserDetails qui renvoie les GrantedAuthorities nécessaires.

Les rôles (comme ils sont utilisés dans de nombreux exemples) ne sont rien de plus que des "autorisations" suivant une convention de nommage selon laquelle un rôle est une GrantedAuthority commençant par le préfixe ROLE_. Rien de plus. Un rôle est juste une GrantedAuthority - une "autorisation" - un "droit". Vous pouvez voir à de nombreux endroits de Spring Security où le rôle avec son préfixe ROLE_ est traité spécialement comme par exemple dans le RoleVoter, où le préfixe ROLE_ est utilisé par défaut. Cela vous permet de fournir les noms de rôles sans le préfixe ROLE_. Avant Spring Security 4, ce traitement spécial des "rôles" n'était pas suivi de manière très cohérente et les autorités et les rôles étaient souvent traités de la même manière (comme vous pouvez le voir dans l'implémentation de la méthode hasAuthority() dans SecurityExpressionRoot - qui appelle simplement hasRole()). Avec Spring Security 4, le traitement des rôles est plus cohérent et le code qui traite des "rôles" (comme le RoleVoter, l'expression hasRole etc.) ajoute toujours le préfixe ROLE_ pour vous. Ainsi, hasAuthority('ROLE_ADMIN') signifie la même chose que hasRole('ADMIN') car le préfixe ROLE_ est ajouté automatiquement. Consultez le guide de migration de Spring Security 3 à 4 pour plus d'informations.

Cependant : un rôle n'est qu'une autorité avec un préfixe spécial ROLE_. Donc dans Spring Security 3, @PreAuthorize("hasRole('ROLE_XYZ')") est la même chose que @PreAuthorize("hasAuthority('ROLE_XYZ')") et dans Spring Security 4, @PreAuthorize("hasRole('XYZ')") est la même chose que @PreAuthorize("hasAuthority('ROLE_XYZ')").

Concernant votre cas d'utilisation :

Les utilisateurs ont des rôles et les rôles peuvent effectuer certaines opérations.

Vous pourriez obtenir des GrantedAuthorities pour les rôles auxquels un utilisateur appartient et les opérations qu'un rôle peut effectuer. Les GrantedAuthorities pour les rôles ont le préfixe ROLE_ et les opérations ont le préfixe OP_. Un exemple d'autorités d'opération pourrait être OP_DELETE_ACCOUNT, OP_CREATE_USER, OP_RUN_BATCH_JOB, etc. Les rôles peuvent être ROLE_ADMIN, ROLE_USER, ROLE_OWNER, etc.

Vos entités pourraient implémenter GrantedAuthority comme dans cet exemple (pseudo-code) :

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

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

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

    public Collection getAllowedOperations() {
        return allowedOperations;
    }
}

@Entity
class User {
    @Id
    private String id;

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

    public Collection getRoles() {
        return roles;
    }
}

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

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

Les IDs des rôles et opérations que vous créez dans votre base de données seraient la représentation GrantedAuthority, par exemple ROLE_ADMIN, OP_DELETE_ACCOUNT, etc. Lorsqu'un utilisateur est authentifié, assurez-vous que toutes les GrantedAuthorities de tous ses rôles et des opérations correspondantes sont renvoyées par la méthode UserDetails.getAuthorities().

Exemple : Le rôle administrateur avec l'ID ROLE_ADMIN a les opérations OP_DELETE_ACCOUNT, OP_READ_ACCOUNT, OP_RUN_BATCH_JOB qui lui sont assignées. Le rôle utilisateur avec l'ID ROLE_USER a l'opération OP_READ_ACCOUNT.

Si un administrateur se connecte, le contexte de sécurité obtenu aura les GrantedAuthorities : ROLE_ADMIN, OP_DELETE_ACCOUNT, OP_READ_ACCOUNT, OP_RUN_BATCH_JOB

Si un utilisateur se connecte, il aura : ROLE_USER, OP_READ_ACCOUNT

Le UserDetailsService se chargerait de collecter tous les rôles et toutes les opérations de ces rôles et de les rendre disponibles par la méthode getAuthorities() dans l'instance UserDetails retournée.

13voto

softjake Points 305

Une autre façon de comprendre la relation entre ces concepts est d'interpréter un RÔLE comme un conteneur d'Autorités.

Les Autorités sont des autorisations fines ciblant une action spécifique parfois associée à une portée de données ou un contexte spécifique. Par exemple, Lire, Écrire, Gérer, peuvent représenter différents niveaux d'autorisations pour une portée d'informations donnée.

De plus, les autorités sont appliquées en profondeur dans le flux de traitement d'une requête tandis que les RÔLES sont filtrés par le filtre de requête bien avant d'atteindre le Contrôleur. Les bonnes pratiques prescrivent la mise en œuvre de l'application des autorités après le Contrôleur dans la couche métier.

En revanche, les RÔLES sont une représentation grossière d'un ensemble d'autorisations. Un RÔLE_LECTEUR aurait seulement l'autorité de Lire ou Voir tandis qu'un RÔLE_EDITEUR aurait à la fois Lire et Écrire. Les rôles sont principalement utilisés pour un premier tri au début du traitement de la requête tel que http. ... .antMatcher(...).hasRole(ROLE_MANAGER)

Le fait que les Autorités soient appliquées en profondeur dans le flux de traitement de la requête permet une application plus fine des autorisations. Par exemple, un utilisateur peut avoir la permission de Lire et Écrire au premier niveau d'une ressource mais seulement la permission de Lire à une sous-ressource. Avoir un RÔLE_LECTEUR limiterait son droit de modifier la ressource de premier niveau car il aurait besoin de l'autorisation d'Écrire pour modifier cette ressource mais un intercepteur @PreAuthorize pourrait bloquer sa tentative de modifier la sous-ressource.

Jake

11voto

coder Points 4358

À ma connaissance GrantedAuthority et les rôles sont les mêmes dans la sécurité spring. La chaîne getAuthority() de GrantedAuthority est le rôle (selon l'implémentation par défaut SimpleGrantedAuthority).

Pour votre cas, vous pouvez peut-être utiliser des rôles hiérarchiques

            ROLE_ADMIN > ROLE_createSubUsers
            ROLE_ADMIN > ROLE_deleteAccounts 
            ROLE_USER > ROLE_viewAccounts

Non pas la solution exacte que vous recherchez, mais j'espère que cela vous aidera

Modifier: Réponse à votre commentaire

Un rôle est comme une permission dans spring-security. En utilisant intercept-url avec hasRole, vous pouvez avoir un contrôle très précis de quelles opérations sont autorisées pour quel rôle/permission.

La façon dont nous gérons dans notre application consiste à définir une autorisation (c'est-à-dire un rôle) pour chaque opération (ou URL rest) par exemple view_account, delete_account, add_account, etc. Ensuite, nous créons des profils logiques pour chaque utilisateur comme admin, guest_user, normal_user. Les profils sont simplement un regroupement logique des autorisations, indépendamment de spring-security. Lorsqu'un nouvel utilisateur est ajouté, un profil lui est attribué (ayant toutes les autorisations admissibles). Maintenant, chaque fois qu'un utilisateur tente d'effectuer une action, l'autorisation/le rôle pour cette action est vérifié par rapport aux GrantedAuthorities de l'utilisateur.

De plus, le Voter de Rôle par défaut utilise le préfixe ROLE_, donc toute autorité commençant par ROLE_ est considérée comme un rôle, vous pouvez modifier ce comportement par défaut en utilisant un préfixe de rôle personnalisé dans le Voter de Rôle et en l'utilisant dans la sécurité spring.

5voto

user Points 61

Comme d'autres l'ont mentionné, je considère les rôles comme des conteneurs pour des autorisations plus granulaires.

Bien que j'ai trouvé que l'implémentation du rôle de hiérarchie manquait de contrôle fin sur ces autorisations granulaires.
J'ai donc créé une bibliothèque pour gérer les relations et injecter les autorisations en tant qu'autorités accordées dans le contexte de sécurité.

Je peux avoir un ensemble d'autorisations dans l'application, quelque chose comme CREATE, READ, UPDATE, DELETE, qui sont ensuite associées au rôle de l'utilisateur.

Ou des autorisations plus spécifiques comme READ_POST, READ_PUBLISHED_POST, CREATE_POST, PUBLISH_POST

Ces autorisations sont relativement statiques, mais la relation des rôles avec elles peut être dynamique.

Exemple -

@Autowired 
RolePermissionsRepository repository;

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

Vous pouvez créer des APIs pour gérer la relation de ces autorisations avec un rôle.

Je ne veux pas copier/coller une autre réponse, voici donc le lien vers une explication plus complète sur SO.
https://stackoverflow.com/a/60251931/1308685

Pour réutiliser mon implémentation, j'ai créé un dépôt. N'hésitez pas à contribuer !
https://github.com/savantly-net/spring-role-permissions

0voto

Ajit Saha Points 24

Il existe des différences subtiles mais significatives entre le rôle et une GrantedAuthority dans Spring Security. Dans Spring Security, chaque GrantedAuthority est définie comme un privilège individuel. Un rôle est attribué à un utilisateur sous forme de GrantedAuthority.

De même, nous pouvons considérer un rôle comme un nom de GrantedAuthority à grain grossier représenté sous forme de chaîne de caractères. Lorsque l'on utilise directement un rôle tel que par le biais d'une expression comme hasRole('ADMIN'), nous restreignons l'accès de manière grossière.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X