Como escrevi anteriormente, o PHPMS mantém um sistema para gerenciar eventos – desde a divulgação de informações, cadastro de eventos, inscrições, pagamentos, envio de mensagens para inscritos e check-in.
Mas o objetivo deste post não é dizer o que já foi dito, quero iniciar uma série de posts onde vou explicar o funcionamento de alguns recursos dentro do Comitiva, convidando todos os desenvolvedores a opinar sobre implementação e contribuir com o projeto.
O assunto de hoje é controle de acesso, então vamos ao que interessa.
Como funciona o controle de acesso no Comitiva?
Utilizamos o componente Auth do CakePHP para cuidar da autenticação (efetuar login, verificar se o usuário está logado e efetuar logout).
Mas precisávamos ir um pouco além da configuração básica, definindo diferentes opções para diferentes tipos de usuários. Para isso, consideramos duas opções iniciais: usar também o Acl Behavior ou ficar apenas com o AuthComponent e criar diferentes actions para diferentes tipos de usuários.
Como possuímos apenas dois tipos de usuários (admin e participant) decidimos pela que seria mais simples inicialmente – mesmo sabendo que a manutenção no futuro poderia ser mais complicada – que foi criar diferentes actions para os tipos de usuários.
Para criar essa funcionalidade, definimos inicialmente um prefixo para cada tipo de usuário (prefixos ‘admin‘ e ‘participant‘). Em seguida configuramos o AuthComponent desta maneira (código extraído do AppController):
//Configure AuthComponent
$this->Auth->authorize = 'controller';
if( !isset($this->params['prefix']) || !( in_array($this->params['prefix'], Configure::read('Routing.prefixes')) ) )
{
// all non-prefixed actions are allowed
$this->Auth->allow('*');
}
Ou seja, toda ação que não tiver prefixo ou o prefixo não estiver definido nas configurações de rota serão públicas (assim é possível, por exemplo, deixar uma página com instruções acessível à qualquer usuário).
Mas como fica essa verificação de tipos no controlador? Como definimos o método de autorização do Auth como ‘controller’, precisamos definir em todos os controladores o método isAuthorized que deve retornar true quando o acesso é aprovado e false caso contrário.
Seguindo a ideia de que cada tipo de usuário possui um prefixo próprio nas ações, nosso método isAuthorized fica desta forma:
if($this->userLogged == TRUE && $this->params['prefix'] == User::get('type'))
{
return true;
}
return false;
Onde o atributo $this->userLogged pertence a classe AppController e sua função é reduzir chamada ao método $Auth->login() e na segunda parte da condição temos uma comparação entre o prefixo da url acessada e o tipo do usuário – se ambos forem iguais, então o acesso está liberado.
Por fim, devemos criar nossas ações para cada tipo de usuário, onde o prefixo será usado para validar o acesso à aquela ação, veja o exemplo da ação “listar pagamentos”:
// ação exclusiva para admin - tem acesso aos pagamentos de todos os outros usuários
public function admin_index($event_id = null)
{
$this->Subscription->recursive = 0;
if(is_numeric($event_id))
{
$this->paginate = array(
'conditions' => array(
'event_id' => $event_id
)
);
}
$this->set(compact('event_id'));
$this->set('subscriptions', $this->paginate());
}
// ação exclusiva para participant - tem acesso somente aos próprios pagamentos
public function participant_index()
{
$this->Subscription->recursive = 0;
$this->set('subscriptions', $this->paginate(array('user_id' => User::get('id'))));
}
Como podem ver, isso permite a criação de diferentes regras de negócio para os diferentes tipos de usuários e embora aumente a quantidade de código “redundante” por repetir alguns procedimentos para todos os tipos de usuários, a leitura e entendimento do código é facilitada – basta ver o prefixo do método (ação) para saber quem terá acesso a ele.