Yii – permissões dos usuários

No último artigo aprendemos a personalizar o funcionamento do login de nosso sistema / site, ao mesmo tempo em que aprendemos a utilizar o Gii para criarmos código automaticamente.
Aqui, iremos personalizar nossa aplicação, para que um determinado tipo de usuário tenha acesso a algumas áreas do site, outro tipo (admins) possam acessar todas as áreas, e usuários que não estejam logados possam também ter acesso a determinadas áreas. Para isso, primeiramente, vamos dar uma olhada no código que o Gii criou para nós.

Quando acessamos o Gii e pedimos para ele criar o CRUD, ele gerou o código necessário para que possamos gerenciar tanto os dados dos usuários quanto dos clientes. Vamos primeiramente acessar as páginas, para vermos o que ele criou:

Usuários
Sem estar logado, acesse a página http://localhost:8080/yii/primeiraapp/?r=usuarios. Com isso, você verá uma página parecida com essa:

Como citado em artigo anterior, ao chamar somente pelo nome de um controller (“usuarios” no caso), o Yii irá procurar pela action Index desse mesmo controller. Foi o que ele fez para exibir-nos a página da imagem acima. Abra então o arquivo protected\controllers\UsuariosControllers.php e procure pela definição da action Index (aqui, ela está a partir da linha  120):

/**
* Lists all models.
*/
public function actionIndex()
{
    $dataProvider=new CActiveDataProvider('Usuarios');
	    this->render('index',array(
	            'dataProvider'=>$dataProvider,
	   ));
}

Na linha 125 geramos um objeto da classe CActiveDataProvider, que é que uma classe “helper”, que disponibiliza-nos objetos da classe Model (no caso, “Usuarios”) que passamos como parâmetro ao instanciá-la. Através da CActiveDataProvider, widgets tais como grids e outros tem acesso a classificação e paginação dos dados. Para mais detalhes, veja no link da ajuda.

A linha 126 chama o método render do controle.
Se você procurar no código da classe (UsuariosController.php), não encontrará a definição do método render. Isso porque a nossa classe herda da classe Controller (protected\components\controller), que por sua vez, herda da classe CController, que é onde esse e outros métodos são definidos.
Ainda na linha 126 e continuando até a linha 128, vemos que o método render está recebendo 2 parâmetros:

  • O primeiro parâmetro (aqui “index”), é o nome da view que será chamada
  • O segundo parâmetro é um array, onde podemos passar quantos parâmetros desejarmos e/ou que nossa view utilize. No caso, passamos apenas um elemento, chamado dataProvider, que receberá o objeto criado anteriormente.

Vamos então dar uma olhada no código da view index. Abra o arquivo protected\views\usuarios\index.php:

<?php
/* @var $this UsuariosController */
/* @var $dataProvider CActiveDataProvider */

$this->breadcrumbs=array(
'Usuarioses',
);

$this->menu=array(
array('label'=>'Create Usuarios', 'url'=>array('create')),
array('label'=>'Manage Usuarios', 'url'=>array('admin')),
);
?>

<h1>Usuarioses</h1>

<?php $this->widget('zii.widgets.CListView', array(
'dataProvider'=>$dataProvider,
'itemView'=>'_view',
)); ?>

A linha 5 define as breadcrumbs, que serão utilizadas pelo tema padrão do Yii.
A linha 9 define os ítens de menu que deverão ser exibidos na mesma página.
A linha 17 exibe o widget CListView, que é usado para exibir dados em forma de lista. Para chamarmos um widget no Yii, utilizamos o método widget da view, passando como parâmetros, primeiramente, o nome da classe (zii.widgets.CListView no caso) que será utilizada para gerar o widget. Os outros parâmetros são relativos ao widget que está sendo instanciado. No caso da CListView, são passados um dataProvider (como citado na action Index) e um outro parâmetro, de nome itemView, que aqui recebe o valor “_view”. Esse parâmetro nada mais é que o nome de outra view (ou subview, se preferir), que definirá como cada registro será exibido na listagem. Veja o arquivo protected\views\usuarios\_view.php.

Agora que já vimos como é o funcionamento básico de uma action que chama uma view, voltaremos ao nosso acesso às páginas do site. Ainda deslogado, clique no menu “Create Usuarios”. O site abrirá a página de login. Logue-se como administrador (com o e-mail que você cadastrou anteriormente) e você conseguirá criar novos usuários. Mas não crie nenhum, ainda não é o momento. Deslogue-se, e acesse novamente o menu “Create Usuarios”, mas desta vez, logue-se como usuario@teste. Você continuará podendo cadastrar usuários.

Porém, em nosso exemplo, teremos que fazer com que somente usuários que sejam administradores possam cadastrar outros usuários. Os usuários “comuns” poderão cadastrar somente clientes. Aliás, a seção de clientes funciona de forma parecida, acesse http://localhost:8080/yii/primeiraapp/?r=clientes e comprove.
Voltando ao cadastro de usuários, como é que o sistema define que (por enquanto) qualquer usuário logado pode ter acesso/alterar a lista de usuários?
Abra novamente o arquivo UsuariosController.php e  procure pelo método accessRules:

/**
 * Specifies the access control rules.
 * This method is used by the 'accessControl' filter.
 * @return array access control rules
 */
 public function accessRules()
 {
	 return array(
		 array('allow',  // allow all users to perform 'index' and 'view' actions
			 'actions'=>array('index','view'),
			 'users'=>array('*'),
		),
		 array('allow', // allow authenticated user to perform 'create' and 'update' actions
			 'actions'=>array('create','update'),
			 'users'=>array('@'),
		 ),
		 array('allow', // allow admin user to perform 'admin' and 'delete' actions
			 'actions'=>array('admin','delete'),
			 'users'=>array('admin'),
		 ),
		 array('deny',  // deny all users
			'users'=>array('*'),
		),
	 );
 }
 

Como o próprio nome diz, o método acessRules define as regras de acesso ao nosso controller. nele, retornamos um array cujos elementos são outros arrays. O primeiro elemento de cada array é a regra (allow ou deny – permitir ou negar). O segundo elemento é outro array, indicando para quais actions são aquelas configurações de acesso. Por fim, o terceiro e último elemento é a verificação de para quais usuários essa regra será aplicada.

Por exemplo, as linhas 30-33 definem que, para as actions index e view (repare que você não precisa colocar actionIndex ou actionView, deve-se suprimir a palavra “action” aqui), qualquer usuário tem acesso (‘users’=>array(‘*’)).
As linhas 34-37 definem que, para as actions create e update, qualquer usuário logado tenha acesso (‘users’=>array(‘@’)).
As linhas 38-41 definem que, para as actions admin e delete, somente  terá acesso o usuário cujo nome seja “admin”. Como alteramos nossa forma de logar, nenhum usuário (por enquanto) conseguirá acessar essas actions. Na próxima seção iremos alterar o sistema para que isso seja possível, e também limitaremos o acesso dos usuários comuns ao cadastro de usuários.
Por último, as linhas 42-44 definem que nenhum usuário poderá acessar actions que não estejam definidas nas linhas acima.

A classe WebUser
No Yii, em uma aplicação web, uma classe é responsável por guardar as informações do usuário logado atualmente. O nome dela é CWebUser.  Ela é acessível através de qualquer parte do sistema, quando chamamos por Yii::app()->user. Ela trabalha em conjunto com a CUserIdentity. E, assim como fizemos com essa, iremos personalizar algumas coisas da classe CWebUser. Para tanto, crie o arquivo protected\components\WebUser.php. Cole/digite o código:


<?php
class WebUser extends CWebUser
{
private $_user;

//get the logged user
function getUser()
{
if ($this->isGuest)
return;

if( $this->_user === null )
{
$this->_user = Usuarios::model()->findByPk( $this->id );
}
return $this->_user;
}

//Admin?
function getIsAdmin()
{
return ( $this->user && $this->user->admin == 1 );
}

}

?>

No método getUser, a linha 9 verifica se há um usuário não logado.
Internamente, o Yii checará se há algum valor atribuído à variável $id. Caso não haja, o return da linha 10 é executado, indicando que não há usuário logado.
Na linha 12, checamos se os dados do usuário (variável interna $_user) já foram carregados. Caso não, o código carrega o usuário de acordo com a variável $id. Já citamos que a classe CWebUser trabalha em conjunto com a CUserIdentity. A classe CWebUser pega o valor da variável $id através do método  getId, que criamos na nossa classe UserIdentity no artigo anterior.

Já o método getIsAdmin será usado para personalizarmos as accessRules de nossos controllers. Ele retorna True caso o usuário logado seja um admin, e False caso não seja.

Mas para que possamos utilizar nossa classe, precisamos avisar ao Yii que ela será usada no nosso gerenciamento de usuários. Para isso, abra o arquivo de configuração (protected\config\main.php) e procure pela seção components (aqui está na linha 34). Altere a subseção user, deixando-a igual ao código abaixo:

// application components
    'components'=>array(
	'user'=>array(
		// enable cookie-based authentication
		'allowAutoLogin'=>true,
		'class'=>'WebUser',
	),

O que fizemos foi, simplesmente, acrescentar o trecho ‘class’=>’WebUser’, indicando ao Yii que essa será nossa classe de acesso aos objetos/dados do usuário.

Personalizando o método accessRules
Abra novamente o arquivo protected\controllers\UsuariosController.php. Altere o método accessRules para que fique igual a esse código:

public function accessRules()
{
    return array(
	array('allow',  // allow all users to perform 'index' and 'view' actions
	'actions'=>array('index','view'),
	'users'=>array('@'),
	),
	array('allow', // allow admin user to perform 'admin' and 'delete' actions
	'actions'=>array('admin','delete','create','update'),
	'expression'=>'$user->isAdmin',
	),
	array('deny',  // deny all users
	'users'=>array('*'),
	),
    );
}

Como você deve ter reparado, alteramos o código para que somente usuários logados tenham acesso às actions index e view.

Já no trecho entre as linhas 34 e 37, vemos algo diferente: ao invés de passarmos o parâmetro users, há um novo parâmetro, chamado expression. Mas o que é esse parâmetro? Resposta: o Yii permite que utilizemos expressões do PHP nas regras de acesso. Com isso, ao passarmos ‘$user->isAdmin’ como o valor do parâmetro expression, fazemos com que o Yii verifique nossa classe WebUser, que criamos há pouco.
Ao verificar o acesso às views que indicamos aqui (admin, delete, create e update), O Yii chama por Yii::app()->user->isAdmin().Caso o método retorne True, ele permite o acesso às views em questão.

Para saber quais tipos de parâmetros o método accessRules aceita, veja a documentação da classe CAccessControlFilter.

Agora, faça o teste: deslogado, tente acessar o método index do controller usuarioshttp://localhost:8080/yii/primeiraapp/?r=usuarios. O sistema irá exibir a página de login:

Logue-se como usuário comum. Será exibida a listagem de usuários:

Clique então em “Create Usuarios” ou “Manage Usuarios”. Será exibida uma mensagem informando que você não está autorizado a acessar essa action:
Relogue-se, mas desta vez, como administrador, e clique novamente em “Manage Usuarios”. Você conseguirá acessar essa área, vendo assim, que nossas permissões de acesso estão funcionando corretamente:
E chegamos ao fim deste artigo. Como exercício, sugiro que faça mudanças nas regras de acesso do controller Clientes (protected\controllers\ClientesController.php). Faça com que qualquer usuário tenha acesso às actions index e view, mas que somente usuários logados (incluindo admins) tenham acesso às actions admin, delete, create e update.
No próximo artigo deste tutorial iremos trabalhar com temas.