Dove dovrebbero svolgersi i controlli di autorizzazione utente in e MVC e da chi?

24

I controlli di autorizzazione dell'utente devono essere effettuati nel modello o nel controller? E chi dovrebbe gestire i controlli delle autorizzazioni, l'oggetto Utente o qualche helper UserManagement?

Dove dovrebbe accadere?

Verifica del controller:

class MyController {
  void performSomeAction() {
    if (user.hasRightPermissions()) {
      model.someAction();
    }
  }
  ...

Avere i controlli nel Controller aiuta a rendere semplici le azioni dei Modelli, così possiamo mantenere tutta la logica sui Controllori.

Verifica del modello:

class MyModel {
  void someAction() {
    if (user.hasRightPermissions()) {
      ...
    }
  }
  ...

Inserendo i controlli nel Modello, complichiamo il Modello, ma assicuriamo anche che non accidentalmente permettiamo agli utenti di fare cose che non dovrebbero essere nel Controller.

E da chi?

Una volta che ci siamo sistemati sul posto, chi dovrebbe fare i controlli? L'utente?

Class User {
  bool hasPermissions(int permissionMask) {
    ...
  }
  ...

Ma non è proprio la responsabilità dell'utente sapere che cosa lui o lei può accedere, quindi forse qualche classe di supporto?

Class UserManagement {
  bool hasPermissions(User user, int permissionMask) {
    ...
  }
  ...

So che è comune porre una sola domanda in, beh, una domanda, ma penso che a questi possa essere data una risposta soddisfacente.

    
posta kba 07.12.2013 - 01:36
fonte

5 risposte

17

Come al solito, "dipende"

  • i controlli delle autorizzazioni funzioneranno funzionano ovunque sia conveniente inserirli,
  • ma se si sta ponendo una domanda tecnica, la risposta potrebbe essere "inserire i controlli nell'oggetto che possiede i dati richiesti per eseguire il controllo" (che è probabilmente il controllore).
  • ma se stai ponendo una domanda filosofica, ti suggerisco una risposta alternativa: non mostrare agli utenti azioni che non possono eseguire .

Quindi nel secondo caso potresti avere il controllo dei permessi nel controller implementato come una proprietà booleana e associare quella proprietà alla proprietà Visible del pulsante o del pannello nell'interfaccia utente che controlla l'azione

come utente, è frustrante vedere i pulsanti per le azioni che non posso eseguire; mi sembra di essere lasciato fuori dal divertimento;)

    
risposta data 07.12.2013 - 06:07
fonte
5

La sicurezza è una preoccupazione trasversale, pertanto deve essere implementata in più livelli. Quello che segue è un esempio per MVC ma il concetto si applica ad altre architetture e / o pattern, devi solo identificare i punti di applicazione.

Dove dovrebbe accadere?

Le viste potrebbero contenere elementi dell'interfaccia utente (widget, pulsanti, menu ecc.) che devono essere visualizzati o meno per alcuni utenti, in base alle loro autorizzazioni. Questa potrebbe essere una responsabilità del motore di visualizzazione , dal momento che non vuoi che ogni vista gestisca da sola. A seconda del tipo di elementi che stai facendo autorizzare su di te, sposta questa responsabilità in un altro posto. Ad esempio, pensa a un menu in cui alcuni elementi devono essere visualizzati e altri no. Gli oggetti possono essere implementati come una lista da qualche parte e filtrare quell'elenco in base alle autorizzazioni e quindi inoltrarlo alla vista.

I controllori rispondono alle richieste, quindi se un utente non ha il permesso di eseguire un'azione deve essere controllato prima che l'azione venga invocata, trasferendo la responsabilità al invocatore di azioni invece di tenerlo nel controller. Questo ha il vantaggio di mantenere pulito il tuo controller e se qualcosa cambia nelle autorizzazioni non devi setacciare i controller per applicare tali modifiche.

Risorse vengono visualizzate in base alle autorizzazioni. Normalmente questo viene fatto a livello di database , dal momento che non vuoi estrarre tutto dal database e quindi applicare le autorizzazioni.

Come puoi vedere, in base a ciò che desideri autorizzare ci sono diversi punti in cui ciò dovrebbe essere fatto. L'obiettivo è quello di essere il meno invadente possibile, in modo che quando la tua politica di sicurezza cambia, puoi facilmente applicarla, preferibilmente senza alterare il codice dell'applicazione. Questo potrebbe non essere valido per le piccole applicazioni, in cui il set di autorizzazioni è abbastanza piccolo e non cambia molto spesso. Tuttavia, nelle applicazioni aziendali la storia è molto diversa.

Chi dovrebbe farlo?

Chiaramente non il modello. Ogni livello dovrebbe avere un punto di applicazione che gestisce l'autorizzazione. Il testo in corsivo sopra evidenzia il possibile punto di applicazione per ogni livello.

Dai un'occhiata a XACML . Non devi implementarlo così com'è, ma ti darà alcune indicazioni che potresti seguire.

    
risposta data 07.12.2013 - 13:26
fonte
1

Io uso il seguente schema. Vale la pena dire che la maggior parte dei controlli delle autorizzazioni utente può essere suddivisa in due casi generali:

  • accesso utente all'azione del controller in base al ruolo utente senza controllo l'azione dei parametri è chiamata con,
  • accesso utente al modello basato su qualsiasi logica o relazione tra particolare utente e modello particolare.

L'accesso all'azione del controller senza il controllo degli attributi viene solitamente implementato nei framework MVC. Questo è semplice: definite le regole, i vostri utenti hanno un ruolo. Devi semplicemente controllare che l'utente abbia il permesso di agire per trovare il suo ruolo nelle regole.

L'accesso utente a un modello particolare dovrebbe essere definito nel modello. (L'attore è una classe utente di base. Supponiamo che possa essere cliente, venditore o ospite.)

interface ICheckAccess
{
    public function checkAccess(Actor $actor, $role);
}

class SomeModel implements ICheckAccess
{
    public function checkAccess(Actor $actor, $role)
    {
        // Your permissions logic can be as sophisticated as you want.
    }
}

Inserire questa logica nel modello porta qualche profitto. Il metodo di controllo dell'accesso può essere ereditato, non è necessario creare classi aggiuntive, è possibile utilizzare i vantaggi OOP generali.

Successivamente, per semplificare il controllo degli accessi, prendiamo alcune ipotesi che sono quasi sempre implementate già per semplicità e buon stile:

  • solitamente i controller sono correlati ad alcune classi di modelli;
  • le azioni che sono verificate per l'accesso prendono come ID un singolo modello come parametro;
  • questo parametro è sempre accessibile in modo uniforme dal metodo della classe del controller di base;
  • l'azione viene inserita nel controller corrispondente al modello che prende l'azione id.

Con questi presupposti, le azioni che utilizzano l'id del modello possono essere associate a una particolare istanza di modello. In effetti, la maggior parte delle azioni può essere facilmente trasformata e spostata per soddisfare le ipotesi sopra indicate.

Quindi, alcune classi di controller astratto di base dovrebbero essere definite ed ereditate.

abstract class ModelController
{
    // Retrieve model from database using id from action parameter.
    public abstract function loadModel($id);

    // Returns rules for user role to pass to SomeModel::checkAccess()
    // Something like array('view' => 'viewer', 'delete' => 'owner', 'update' => 'owner')
    public abstract function modelRules();

    public abstract fucntion getIdParameter();

    public function filterModelAccess()
    {
        $id = $this->getIdParameter();
        if(!$this->checkModelAccess($id))
            throw new HttpException(403);
    }

    public function checkModelAccess($id)
    {
        $model = $this->loadModel($id);
        $actor = My::app()->getActor();
        $rules = $this->modelRules();
        $role = $rules[My::app()->getActionName()];
        return $model->chechAccess($actor, $role);
    }
}

Puoi chiamare il metodo SomeController :: checkModelAccess ($ id) quando costruisci i menu e decidi se mostrare qualche link.

    
risposta data 22.02.2014 - 09:23
fonte
1

In entrambi i modelli e Visualizza

Nella vista - perché l'interfaccia utente non dovrebbe mostrare gli elementi dell'interfaccia utente limitati all'utente corrente

(come, per esempio, il pulsante "Elimina" dovrebbe essere mostrato alle persone con permessi appropriati)

Nel modello - perché la tua app probabilmente ha una sorta di API, giusto? L'API deve controllare anche le autorizzazioni e probabilmente ri-utilizza il Modello.

(come, ad esempio, hai il pulsante "Elimina" nell'interfaccia utente e il metodo "http: / server / API / DeleteEntry / 123" allo stesso tempo

    
risposta data 09.09.2014 - 21:01
fonte
0

MVC è un modello di presentazione. Poiché tale visualizzazione e responsabile del trattamento dovrebbero avere solo responsabilità in merito alla presentazione. Alcune autorizzazioni si applicano alla presentazione, come una modalità esperta, funzionalità di interfaccia utente sperimentale o diversi progetti. Questi possono essere gestiti dal controller MVC.

Molti altri tipi di permessi sono rilevanti su diversi livelli dell'applicazione. Ad esempio se vuoi avere utenti che possono solo visualizzare i dati e non cambiare le cose:

  • il livello di presentazione deve nascondere le funzioni di modifica
  • Se viene comunque chiamata una funzione di modifica, questa potrebbe / dovrebbe essere rilevata (dalle parti specifiche dell'applicazione del livello aziendale, non dalla parte specifica del dominio di esso - TrainEditor, non Train) e probabilmente causa un'eccezione
  • Il livello di accesso ai dati può anche controllare le scritture, ma per tipi di permessi più complessi che richiedono rapidamente troppa conoscenza del livello aziendale per essere una buona idea.

C'è qualche duplicazione in questo approccio. Ma dato che la presentazione è solitamente volatile, si può fare un buon caso per controllare i permessi nella parte solitamente più stabile dell'applicazione, anche se ciò significa alcuni controlli ridondanti nel caso in cui il livello di presentazione funzioni come previsto.

    
risposta data 07.12.2013 - 15:57
fonte

Leggi altre domande sui tag