Uso il seguente schema. Vale la pena dire che la maggior parte dei controlli delle autorizzazioni degli utenti può essere suddivisa in due casi generali:
- l'accesso dell'utente all'azione del controller in base al ruolo utente senza verificare i parametri con cui viene chiamata l'azione,
- accesso dell'utente al modello basato su qualsiasi logica o relazione tra un determinato utente e un determinato modello.
L'accesso all'azione del controller senza il controllo degli attributi viene generalmente implementato nei framework MVC. Questo è semplice: definisci le regole, i tuoi utenti hanno un ruolo. È sufficiente verificare che l'utente disponga dell'autorizzazione all'azione per cercare il suo ruolo nelle regole.
L'accesso dell'utente a un modello particolare deve essere definito nel modello. (L'attore è la 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 un certo profitto. Il metodo di controllo dell'accesso può essere ereditato, non è necessario creare alcuna classe aggiuntiva, è 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:
- di solito i controller sono correlati ad alcune classi di modelli;
- le azioni a cui è stato verificato l'accesso accettano come parametro un singolo ID modello;
- questo parametro è sempre accessibile in modo uniforme dal metodo della classe controller di base;
- l'azione viene posizionata nel controller corrispondente al modello che l'azione ID esegue.
Con questi presupposti, le azioni che utilizzano l'ID modello possono essere associate a un'istanza del modello particolare. In effetti, la maggior parte delle azioni può essere facilmente trasformata e spostata per adattarsi alle ipotesi di cui sopra.
Quindi, è necessario definire ed ereditare alcune classi di controller astratte di base.
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 tuoi menu e decidi se mostrare qualche link.