Come conservare i diritti di accesso basato sui ruoli nell'applicazione web?

6

Attualmente lavora su un sistema di tipo CRM basato sul web che si occupa di vari moduli come aziende, contatti, progetti, progetti secondari, ecc. Un tipico sistema di tipo CRM (modulo web asp.net, C #, backend SQL Server). Abbiamo in programma di implementare la sicurezza basata sui ruoli in modo che fondamentalmente un utente possa avere uno o più ruoli.

I ruoli verrebbero suddivisi in base al tipo di modulo, ad esempio:

-Società

-Contattare

E poi con le azioni per quel modulo, per esempio ogni modulo finirebbe con una tabella come questa:

Role1 Example:

    Module   Create  Edit        Delete   View
    Company   Yes    Owner Only    No     Yes
    Contact   Yes    Yes           Yes    Yes

Nel caso precedente Role1 ha due tipi di modulo (Azienda e Contatto). Per la società, la persona assegnata a questo ruolo può creare società, può visualizzare le società, può solo modificare i record che ha creato e non può eliminare. Per questo stesso ruolo per il modulo contatta questo utente può creare contatti, modificare contatti, eliminare contatti e visualizzare i contatti (in pratica i diritti completi).

Mi chiedo se sia meglio entrare nel sistema per eseguire il ruolo dell'utente con qualcosa del tipo:

List<Role> roles;

Dove la classe Role avrebbe una sorta di List<Module> modules; (può contenere Azienda, Contatto, ecc.).? Qualcosa con l'effetto di:

class Role{
string name;
string desc;
List<Module> modules;
}

E la classe azione modulo avrebbe una serie di azioni (Crea, Modifica, Elimina, ecc.) per ogni modulo:

class ModuleActions{
List<Action> actions;
}

E l'azione ha un valore se l'utente può eseguire il diritto:

class Action{
string right;
}

Solo un'idea approssimativa, so che l'azione potrebbe essere un enum e ModuleAction può probabilmente essere eliminato con un List<x, y> . La mia domanda principale è quale sarebbe il modo migliore per archiviare queste informazioni in questo tipo di applicazione: Devo memorizzarlo nello stato Sessione utente (ho una sessione di sessione in cui gestisco le cose relative all'utente). Generalmente lo carico durante il caricamento iniziale dell'applicazione (global.asax). Posso semplicemente virare su questa sessione.

O dovrebbe essere caricato all'evento di caricamento della pagina di ciascun modulo (caricamento della pagina della società ecc.). Alla fine ho bisogno di essere in grado di nascondere / mostrare vari pulsanti / div in base al ruolo dell'utente e questo è quello che mi ha fatto pensare di caricarlo tramite la sessione.

Qualsiasi esempio o punto sarebbe fantastico.

    
posta JonH 13.06.2014 - 04:22
fonte

4 risposte

3

Bene, penso che il tuo design sia perfetto. Ti consiglierei solo una cosa semplice su come memorizzare i ruoli. Ho qui un sistema che ha quasi gli stessi concetti. Non si basa su ruoli come per il nome.

Quindi ho un oggetto sessione utente con oggetti di tipo Map che memorizzano le autorizzazioni che l'utente ha. E questo oggetto Mappa è pieno su demmand sarà qualcosa del tipo:

public class UserSession {
    HashMap<Application, Action> map;

    public boolean hasPermissionApp( Application app ){
        if ( !map.containsKey(app) ){
            //check if the user has the permission on the DB or whatever you store it
            //if it has add it to the map with the action that 
            //it came along and return true
            //if it hasn't return false
        }
        return true;
    }

    public boolean hasPermissionAction( Application app, Action act ) {
        if ( hasPermissionApp(app) ){
            if ( !map.get(app).containsKey(act) ){
                //check if the user has permission to that action of the app
                //if it has add to the map and return true
                //if not return false
            }
        }
        return false;
    }
}

In questo modo si carica permisson utente e lo si memorizza con demmand e non si esegue il sovraccarico dell'oggetto session con il set completo di permessi dell'utente.

Modifica

Come OP ha chiesto sui commenti:

  • Riempi questa hashmap ad ogni sorta di evento click che richiede permessi di ruolo?

La risposta è quasi questa. Quando l'utente accede a un'applicazione l'oggetto della sessione utente è vuoto, quindi per l'applicazione che sta effettuando l'accesso verificherei se ha accesso e, in caso affermativo, lo aggiungo alla mappa con la prima azione che è stata chiamata da tale applicazione diciamo 'Visualizza'. E con questa azione l'utente può vedere il modulo di ricerca.

Qui puoi avere due approcci. Quale è quello che hai chiesto!

  • Verifica i permessi quando l'utente attiva gli eventi come con questa azione 'Visualizza' può vedere l'intero modulo con i pulsanti cerca, aggiungi, cancella (o qualsiasi altro) Ma l'autorizzazione verrà verificata solo quando l'utente premi il bottone. Poi se hai aggiunto alla mappa o gli invii un messaggio che dice che non ha quell'autorizzazione.

  • Verifica il permesso durante il rendering delle azioni. Mostra i pulsanti sul modulo solo se l'utente ha l'azione appropriata ad esso associata. Quindi diciamo che stai usando una libreria di componenti come Richfaces sarebbe come questa:

<a4j:commandButton rendered="#{userSessionObject.hasPermissionAction('appBla','search')}" ..... />

E dal momento che questo è stato creato sulla costruzione della pagina, la mappa verrà riempita su ogni controllo autorizzato sulla pagina o su altre risorse.

E sulla mia applicazione scelgo per il secondo approccio, perché non penso che abbia senso mostrare un pulsante a un utente che non ha accesso ad esso.

Modifica 2

Una cosa che forse è utile è che associo un tempo di thread (tempo configurabile) alla sessione utente che pulisce le mappe su userSessionObject, quindi se qualche amministratore modifica i permessi a quell'utente ad un certo punto avrà le sue autorizzazioni aggiornato automaticamente, non esattamente al prompt ma questo era un requisito accettabile per questo particolare sistema.

    
risposta data 27.06.2014 - 15:22
fonte
1

Ero abituato a lavorare su un sistema con un numero fisso di tabelle / directory (diverso dal tuo), quindi non ho usato lo schema di sicurezza basato sul ruolo come quello del tuo (o del file system o del DB SQL) . Ho usato il livello di accesso lineare. Ad alto livello, la cosa è simile però, specialmente con la tua domanda.

Ciononostante, ovunque e comunque memorizzi il diritto di accesso sul lato client, non c'è alcuna garanzia che si tratti di un riflesso accurato di ciò che è presente nella fonte (il DB).

  1. Carica l'accesso quando l'utente esegue l'accesso. La conservazione dell'accesso a destra in un oggetto di sessione va bene.
  2. Convalidare ogni azione sul livello logico sul back-end
  3. Extra: quando un'azione non viene completata, il backend invierà il feedback sulle modifiche nel diritto di accesso
  4. Opzione aggiuntiva 1: quando viene ricevuto un feedback, il back-end può anche inviare un altro chunk per codificare i nuovi diritti di accesso
  5. Opzione aggiuntiva2: quando viene ricevuto il feedback, il front-end suggerisce all'utente di riconnettersi
risposta data 24.06.2014 - 10:04
fonte
0

Ci dovrebbe essere pochissimo overhead associato con ottenere i permessi utente sul caricamento della pagina, quindi fatelo. Non utilizzare la sessione per archiviare molte cose. Ciò consentirà alle autorizzazioni di essere modificate dinamicamente dagli amministratori (in modo che l'utente non debba effettuare nuovamente il login).

Piuttosto che sviluppare un'infrastruttura di ruolo dettagliata, perché non considerare qualcosa di più semplice come assegnare tag di autorizzazione a un utente, ad es. azienda: creare, azienda: modifica, ecc. Questi possono essere interpretati esattamente come farebbe la tua attuale infrastruttura; tuttavia, ciò consentirà una certa flessibilità aggiuntiva consentendo l'assegnazione delle autorizzazioni a più azioni discrete (ad esempio, non solo le operazioni CRUD).

Infine, qualsiasi autorizzazione concessa nel client deve essere verificata sul server quando l'utente invia la sua azione. Non possiamo semplicemente fidarci del cliente. Quindi, sul client o sul server controllerai i tag di autorizzazione di un utente e farai la cosa giusta. Sul lato client questo potrebbe significare cambiare l'interfaccia. Sul lato server, ciò potrebbe significare rifiutare una transazione in cui sembra che l'utente abbia in qualche modo eluso le nostre autorizzazioni (ad esempio, ha tentato di creare un'azienda in cui ciò non era consentito).

    
risposta data 23.06.2014 - 15:38
fonte
0

Penso che sarebbe meglio memorizzare un List<Action> nella sessione. Risolvi questo elenco in base ai ruoli che l'utente ha all'inizio della sessione.

A meno che le autorizzazioni cambino spesso, è sufficiente che le autorizzazioni utente vengano aggiornate su ogni accesso.

Su un sidenote, non lo progetterei in modo che Role abbia un List<Module> ma invece un List<Action> .

    
risposta data 24.06.2014 - 08:41
fonte

Leggi altre domande sui tag