Differenza tra ruolo e autorizzazione concessa in Spring Security


227

Esistono concetti e implementazioni in Spring Security, come l' GrantedAuthorityinterfaccia per ottenere un'autorità per autorizzare / controllare un accesso.

Vorrei che le operazioni consentite, come createSubUsers o deleteAccounts , che consentissi a un amministratore (con ruolo ROLE_ADMIN).

Mi confondo come i tutorial / demo che vedo online. Provo a collegare ciò che ho letto, ma penso che trattiamo i due in modo intercambiabile.

Vedo hasRoleconsumare una GrantedAuthoritystringa? Sicuramente sto sbagliando a capire. Cosa sono concettualmente in Spring Security?

Come posso memorizzare il ruolo di un utente, separato dalle autorità per quel ruolo?

Sto anche guardando l' org.springframework.security.core.userdetails.UserDetailsinterfaccia che viene utilizzata nel DAO di riferimento del provider di autenticazione, che consuma un User(nota l'ultima GrantedAuthority):

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

O c'è un altro modo per differenziare gli altri due? O non è supportato e dobbiamo crearne uno nostro?

Risposte:


365

Pensa a un GrantedAuthority come a un "permesso" o un "diritto". Tali "permessi" sono (normalmente) espressi come stringhe (con il getAuthority()metodo). Queste stringhe ti consentono di identificare le autorizzazioni e lasciare che i tuoi elettori decidano se concedere l'accesso a qualcosa.

È possibile concedere diverse autorizzazioni (autorizzazioni) agli utenti inserendole nel contesto di sicurezza. Normalmente lo fai implementando il tuo UserDetailsService che restituisce un'implementazione UserDetails che restituisce le necessarie GrantedAuthorities.

I ruoli (come vengono utilizzati in molti esempi) sono solo "autorizzazioni" con una convenzione di denominazione che afferma che un ruolo è un GrantedAuthority che inizia con il prefisso ROLE_. Non c'è altro. Un ruolo è solo un GrantedAuthority - un "permesso" - un "diritto". Si vedono molti posti nella sicurezza primaverile in cui il ruolo con il suo ROLE_prefisso viene gestito specialmente come ad es. In RoleVoter, dove il ROLE_prefisso viene utilizzato come predefinito. Ciò consente di fornire i nomi dei ruoli senza il ROLE_prefisso. Prima di Spring Security 4, questa particolare gestione dei "ruoli" non è stata seguita in modo molto coerente e le autorità e i ruoli sono stati spesso trattati allo stesso modo (ad es.hasAuthority()hasRole()). Con Spring Security 4, il trattamento dei ruoli è più coerente e il codice che si occupa di "ruoli" (come RoleVoter, l' hasRoleespressione, ecc.) Aggiunge sempre il ROLE_prefisso per te. Quindi hasAuthority('ROLE_ADMIN')significa lo stesso hasRole('ADMIN')perché il ROLE_prefisso viene aggiunto automaticamente. Consulta la guida alla migrazione da 3 a 4 di Spring Security per ulteriori informazioni.

Ma comunque: un ruolo è solo un'autorità con un ROLE_prefisso speciale . Quindi in Spring Security 3 @PreAuthorize("hasRole('ROLE_XYZ')")è uguale a @PreAuthorize("hasAuthority('ROLE_XYZ')")e in Spring Security 4 @PreAuthorize("hasRole('XYZ')")è uguale a @PreAuthorize("hasAuthority('ROLE_XYZ')").

Per quanto riguarda il tuo caso d'uso:

Gli utenti hanno ruoli e ruoli possono eseguire determinate operazioni.

Potresti finire GrantedAuthoritiesper i ruoli a cui appartiene un utente e le operazioni che un ruolo può svolgere. Il GrantedAuthoritiesper i ruoli ha il prefisso ROLE_e le operazioni hanno il prefisso OP_. Un esempio per le autorità operazione potrebbe essere OP_DELETE_ACCOUNT, OP_CREATE_USER, OP_RUN_BATCH_JOBecc ruoli possono essere ROLE_ADMIN, ROLE_USER, ROLE_OWNERetc.

Potresti finire per avere le tue entità implementate GrantedAuthoritycome in questo esempio (pseudo-codice):

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

Gli ID dei ruoli e delle operazioni creati nel database sarebbero la rappresentazione GrantedAuthority, ad esempio ROLE_ADMIN, OP_DELETE_ACCOUNTecc. Quando un utente viene autenticato, assicurarsi che tutte le Autorità Granted di tutti i suoi ruoli e le operazioni corrispondenti vengano restituite da UserDetails.getAuthorities () metodo.

Esempio: il ruolo admin con id ROLE_ADMINha le operazioni OP_DELETE_ACCOUNT, OP_READ_ACCOUNT, OP_RUN_BATCH_JOBassegnati ad esso. Il ruolo utente con ID ROLE_USERha l'operazione OP_READ_ACCOUNT.

Se un utente di amministrazione nel contesto di protezione risultante avrà le GrantedAuthorities: ROLE_ADMIN, OP_DELETE_ACCOUNT, OP_READ_ACCOUNT,OP_RUN_BATCH_JOB

Se un utente accede, esso avrà: ROLE_USER,OP_READ_ACCOUNT

UserDetailsService si occuperà di raccogliere tutti i ruoli e tutte le operazioni di tali ruoli e di renderli disponibili con il metodo getAuthorities () nell'istanza UserDetails restituita.


2
Grazie! Ho cercato dappertutto perché "hasRole ('rolename')" non funzionasse nella primavera 4 -> La loro documentazione non era esattamente veloce da sfogliare. Solo un breve "trova e sostituisci" e sono tornato in pista!
Jørgen Skår Fischer,

12
Questa è un'ottima risposta Una cosa da chiarire per spiegare in modo leggermente diverso, hasRole('xyz')in Spring Security 4 si aspetta che tu abbia il prefisso ROLE_ mentre hasAuthority('xyz')non si aspetta il prefisso e valuta esattamente ciò che viene passato. Ho usato questa soluzione, ma da hasRole('OP_MY_PERMISSION')allora ho riscontrato problemi la ROLE_ era necessario prefisso. Invece, avrei dovuto usare il hasAuthority('OP_MY_PERMISSION')dato che non avevo il prefisso.
randal4,

@james puoi guardare questa domanda stackoverflow.com/questions/41500031/…
saurabh kumar,

1
In JSTL springframework.org/security/tags <sec:authorize access="hasRole('ADMIN')">è lo stesso di<sec:authorize access="hasRole('ROLE_ADMIN')">
Alex78191

1
Sì. OP_ è solo un prefisso arbitrario. ROLE_ ha il suo significato speciale in alcune implementazioni di primavera.
James,

9

AFAIK GrantedAutorità e ruoli sono gli stessi nella sicurezza primaverile. La stringa getAuthority () di GrantedAuthority è il ruolo (secondo l'implementazione predefinita SimpleGrantedAuthority).

Per il tuo caso, puoi usare i ruoli gerarchici

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

Non è il sol esatto che stai cercando, ma spero che ti aiuti

Modifica : Rispondi al tuo commento

Il ruolo è come un'autorizzazione per la sicurezza primaverile. l'uso di interccept-url con hasRole fornisce un controllo molto preciso di quale operazione è consentita per quale ruolo / autorizzazione.

Il modo in cui gestiamo nella nostra applicazione è, definiamo l'autorizzazione (cioè il ruolo) per ogni operazione (o resto URL) per es. View_account, delete_account, add_account ecc. Quindi creiamo profili logici per ogni utente come admin, guest_user, normal_user. I profili sono solo raggruppamenti logici di autorizzazioni, indipendenti dalla sicurezza primaverile. Quando viene aggiunto un nuovo utente, gli viene assegnato un profilo (con tutte le autorizzazioni consentite). Ora, ogni volta che l'utente tenta di eseguire alcune azioni, l'autorizzazione / il ruolo per quell'azione viene verificato rispetto alle autorizzazioni concesse all'utente.

Anche DefaultV RoleVoter utilizza il prefisso ROLE_, pertanto qualsiasi autorità che inizia con ROLE_ viene considerata come ruolo, è possibile modificare questo comportamento predefinito utilizzando un RolePrefix personalizzato nell'elettore di ruoli e utilizzandolo nella sicurezza primaverile.


1
Grazie per l'aiuto. La gerarchia sembra essere qualcos'altro. Il modo in cui sto pensando di farlo ora (se devo usare Spring Security) è memorizzare sia il ruolo che l'autorità nella stessa lista e usare il predicato hasRole per eseguire i controlli per entrambi. Pensandoci di più, questo è probabilmente lasciato intenzionale dai ragazzi di Spring Security? Esiste la possibilità di utilizzare l'URL di intercettazione oltre a controllare utilizzando hasRole nell'elenco completo di ruoli e privilegi / autorità - o altre domande di autorizzazione. Inoltre, qual è la necessità di aggiungere il prefisso ROLE_? È una convenzione?
Chinmay,

7

Un altro modo per comprendere la relazione tra questi concetti è interpretare un RUOLO come un contenitore di autorità.

Le autorità sono autorizzazioni dettagliate che mirano a un'azione specifica abbinata a volte a ambito o contesto di dati specifici. Ad esempio, Leggi, Scrivi, Gestisci, può rappresentare vari livelli di autorizzazioni per un determinato ambito di informazioni.

Inoltre, le autorità vengono applicate in profondità nel flusso di elaborazione di una richiesta mentre i ruoli vengono filtrati in base al filtro di richiesta prima di raggiungere il controller. Le migliori pratiche prescrivono l'implementazione delle autorità di controllo oltre il controller nel livello aziendale.

D'altra parte, ROLES sono rappresentazioni a grana grossa di un insieme di autorizzazioni. Un ROLE_READER avrebbe solo l'autorizzazione di lettura o visualizzazione mentre un ROLE_EDITOR avrebbe sia lettura che scrittura. I ruoli vengono utilizzati principalmente per una prima proiezione alla periferia dell'elaborazione della richiesta come http. ... .antMatcher (...). hasRole (ROLE_MANAGER)

Le autorità che vengono applicate in modo approfondito nel flusso di processo della richiesta consentono un'applicazione più fine dell'autorizzazione. Ad esempio, un utente può disporre dell'autorizzazione di Lettura in scrittura per il primo livello di una risorsa, ma solo Lettura in una sotto-risorsa. Avere un ROLE_READER limiterebbe il suo diritto di modificare la risorsa di primo livello poiché ha bisogno dell'autorizzazione in scrittura per modificare questa risorsa, ma un intercettore @PreAuthorize potrebbe bloccare il suo tentativo di modificare la sub-risorsa.

Jake


2

Come altri hanno già detto, penso ai ruoli come contenitori per autorizzazioni più granulari.

Anche se ho trovato che l'implementazione del ruolo gerarchico mancava di un controllo accurato di queste autorizzazioni granulari.
Quindi ho creato una libreria per gestire le relazioni e iniettare le autorizzazioni come autorizzazioni concesse nel contesto della sicurezza.

Potrei avere una serie di autorizzazioni nell'app, qualcosa come CREATE, READ, UPDATE, DELETE, che sono quindi associate al ruolo dell'utente.

O autorizzazioni più specifiche come READ_POST, READ_PUBLISHED_POST, CREATE_POST, PUBLISH_POST

Queste autorizzazioni sono relativamente statiche, ma la relazione dei ruoli con esse può essere dinamica.

Esempio -

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

È possibile creare API per gestire la relazione di queste autorizzazioni con un ruolo.

Non voglio copiare / incollare un'altra risposta, quindi ecco il link per una spiegazione più completa su SO.
https://stackoverflow.com/a/60251931/1308685

Per riutilizzare la mia implementazione, ho creato un repository. Per favore, sentitevi liberi di contribuire!
https://github.com/savantly-net/spring-role-permissions

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.