Pratiche standard per il controllo degli accessi (modello di progettazione)

9

Sto guardando il mio design dell'interfaccia e sto cercando di stabilire quale sia il modo più "corretto" per implementare il controllo degli accessi basato sui ruoli, dato un user e un subject che la user vorrebbe accedere.

Per quanto posso vedere, ho tre opzioni principali (una quarta è una bastardizzazione dei primi tre e una quinta è una modifica del quarto):

  1. Esegui una query su subject con un elenco di autorizzazioni che user ha - subject.allowAccess(user.getPermissionSet)
  2. Esegui una query su user con un elenco di autorizzazioni che subject richiede - user.hasPermissionTo(subject.getRequiredPermissions())
  3. Interroga una terza parte per individuare le intersezioni delle autorizzazioni - accessController.doPermissionSetsIntersect(subject.permissionSet, user.getPermissionSet())
  4. Esegui una query su subject / user , delegando la "decisione" a una classe di terze parti
  5. Chiedi a user di accedere a subject e genera un errore se l'accesso non è consentito

Mi sto appoggiando all'opzione numero quattro: il subject contiene un campo accessController , dove le chiamate a subject.userMayAccess(User user) delegano l'operazione a la:

class Subject {
    public function display(user) {
        if(!accessController.doPermissionSetsIntersect(this.permissionSet, user.getPermissionSet())) {
            display403(); //Or other.. eg, throw an error..
        }
    }
}

.. ma questo solleva ulteriori domande:

  • il accessController dovrebbe essere un campo rispetto a una classe statica ..?
  • Se un subject conosce quali autorizzazioni sono richieste per poterlo visualizzare?
  • dove entra in gioco il principio della minima conoscenza, rispetto a chiamare subject.display() ? I chiamanti di subject.display() dovrebbero mai sapere che il controllo degli accessi è in vigore? (dove subject.display() è un "metodo modello finale")
  • ha subject.display() gestisce il controllo degli accessi, generando un'eccezione in cui l'utente non dispone dell'autorizzazione richiesta?

Quale sarebbe considerata la "migliore pratica" in questa situazione? Dove dovrebbe effettivamente avere la responsabilità dell'esecuzione dei controlli?

Poiché questo è un po 'sia un esercizio accademico che poi progredirà nell'implementazione, i riferimenti ai modelli di progettazione sarebbero apprezzati.

    
posta kwah 19.08.2013 - 22:13
fonte

2 risposte

6

La migliore pratica è usare qualcosa conosciuto come pattern Interceptor per intercettare le chiamate verso aree protette.

Ciò può essere ottenuto utilizzando l'AOP o le preoccupazioni trasversali applicate ai punti di accesso degli accessi.

L'argomento non dovrebbe mai sapere chi è in grado di vederlo. Ciò complica inutilmente il codice soggetto e non vi è alcun motivo per farlo, a meno che non si fornisca inavvertitamente un meccanismo di accesso diretto alla stessa funzione.

Preferibilmente il chiamante e il destinatario non dovrebbero conoscere l'accesso, a parte la gestione dei rifiuti. Tuttavia, il problema dipenderà dal sistema su cui si sta implementando e da come si ottiene l'accesso alle credenziali di sicurezza / principale per il chiamante. Ad esempio, nei sistemi SOAP questa informazione viene aggiunta all'intestazione di un messaggio SOAP, mentre in un sistema Windows sarebbe disponibile tramite il meccanismo di autenticazione di Windows.

Se si utilizza l'approccio del modello AOP o dell'intercettatore, si genererebbero tutte le eccezioni necessarie e spetterebbe al client (chiamante) gestire tutte le eccezioni generate.

In questo modo mantieni il tuo cliente, il tuo servizio e il tuo codice di autenticazione separati senza alcuna mescolanza di conoscenze o funzionalità.

    
risposta data 20.08.2013 - 04:31
fonte
2

Penso che la tua opzione 3 sia la più vicina, ma invece di interrogare user e subject sui loro set di permessi dovresti passare user e subject al controller di accesso.

class Subject {
    public function display(user) {
        if(!accessController.checkAccess(this, user, AccessControl.Read)) {
            display403(); //Or other.. eg, throw an error..
        }
    }
}

Il controller di accesso dovrebbe essere responsabile sia del recupero dei set di autorizzazioni sia del controllo se l'accesso è sufficiente. In questo modo si isolano sia la logica di archiviazione che la logica di controllo nel controller di accesso, separati sia dall'utente che dall'oggetto.

L'altro elemento mancante nel tuo esempio è l'operazione che viene eseguita. Alcuni utenti potrebbero avere il diritto di leggere alcuni dati ma non di aggiornarli, eliminarli, eseguirli, ecc. Quindi si potrebbe avere un metodo checkAccess sul controller di accesso con tre parametri: user , subject , operation . Potresti anche fornire alcune informazioni aggiuntive da checkAccess per restituire informazioni sul motivo per cui l'accesso non è stato concesso.

Ad esempio, delegare tutto questo al controller di accesso in seguito consente di sostituire il modo in cui le autorizzazioni sono rappresentate. Potresti iniziare con il controllo degli accessi basato sui ruoli e passare alle attestazioni successive in seguito. È possibile memorizzare le autorizzazioni in una struttura semplice per iniziare e successivamente aggiungere gruppi gerarchici / ruoli e operazioni permissibili su diversi tipi di argomenti. Non mettere i set di permessi nell'interfaccia aiuta ad abilitare questo.

Se si utilizza AOP o un codice boilerplate per collegarlo, a mio parere, è meno importante.

    
risposta data 21.08.2016 - 20:23
fonte

Leggi altre domande sui tag