Para um bom entendimento deste artigo faz-se necessário dos conhecimentos da estrutura do Yii framework, assim como suas principais classes e como o Yii implementa o conceito de ActiveRecord para criar suas aplicações. Confiraalguns artigos, aqui mesmo do portal DevMedia, uma breve introdução ao Yii Framework.

Assim como todos os grandes softwares do mercado, um bom sistema de autenticação de usuários é uma das principais chaves para o sucesso no mundo do desenvolvimento de software. Grandes corporações, principalmente instituições que lidam com transações financeiras, dependem de forma direta de um sistema de segurança confiável. Aqui será visto como o Yii Framework lida, juntamente ao banco de dados, da manipulação e autenticação dos usuários do sistema. Será visto a correta utilização das classes CWebUser e CUserIdentity, as quais são responsáveis pelo sistema de autenticação criado pelo Yii Framework.

Nota: A versão do Yii Framework utilizada como base neste texto é a 1.1. Embora o framework já disponibilize sua versão 2, no momento da criação deste artigo, esta encontra-se ainda em fase beta.

Sistema de autenticação do Yii Framework.

Assim como em todo sistema de autenticação por banco de dados, o Yii realiza a consulta (SELECT) na tabela onde estão armazenados os registros de usuários, verifica se os valores digitados em login e senha conferem com algum registro e autentica o usuário. A única diferença é que o framework utiliza do ActiveRecord para interagir com a base de dados.

A DevMedia possui ótimos cursos de PHP, se você pretende se tornar um ótimo programador PHP, não deixe de conferir.

Vale destacar também que o Yii utiliza o conceito de componentes, onde é possível guardar trechos de código que poderão ser acessados por todo o sistema. Neste artigo será implementado o componente “user”, que já existe no core do framework.

Nota: Mais informações sobre componentes acesse http://www.yiiframework.com/doc/guide/1.1/pt/basics.component

Classe CUserIdentity:é a classe responsável por manipular as informações do Usuário já logado. Além disso, é nela que se localiza o método authenticate(), onde serão autenticados os dados submetidos pelo usuário.

Classe CWebUser:é a classe onde ficarão todas as regras de negócio que se referem ao nível de permissão dos usuários cadastrados no sistema. A CWebUser agirá juntamente à CUserIdentity para realizar a autenticação dos dados e a verificação do nível pertencente do usuário.

No Framework Yii, a classe CWebUser é usada como um componente da aplicação, cujo ID retorna a instância do usuário. É importante saber que, em qualquer local do sistema, é possível acessar o usuário atualmente logado através do método app(), presente na classe Yii. Para retornar o usuário acesse Yii::app()->user. É nesta classe que ficarão as regras de negócio da entidade Usuário, ou seja, os méotodos responsáveis pela verificação do nível de acesso de cada usuário logado no sistema.

Criando Sistema de Login na prática

Depois deste breve resumo sobre a estrutura interna de autenticação do Yii, vamos ao exemplo prático.

Execute o código da Listagem 1 em seu banco de dados para criar a tabela de usuários. Ela terá o nome de Administrador.

Listagem 1. Criação da tabela de usuários


  --
  
  -- Table structure for table `Administrador`
  
  --
  
   
   
  CREATE TABLE IF NOT EXISTS `Administrador` (
  
  `id` int(11) NOT NULL,
  
    `nivel` int(11) NOT NULL,
  
    `nome` varchar(300) NOT NULL,
  
    `email` varchar(300) NOT NULL,
  
    `usuario` varchar(300) NOT NULL,
  
    `senha` varchar(300) NOT NULL
  
  ) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
  
   
   
   
  --
  
  -- Indexes for table `Administrador`
  
  --
  
  ALTER TABLE `Administrador`
  
   ADD PRIMARY KEY (`id`);
  
   
  ALTER TABLE `Administrador`
  
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=4;

Confira na Figura 1 a estrutura física da tabela Administrador criada.

Tabela Administrador

Figura 1. Tabela Administrador.

Criação do modelo Administrador

Acesse http://SEU_ENDERECO/index.php/gii e se logue com a sua senha. Confira na Figura 2 a tela de login do Gii.

Tela inicial do utilitário Gii

Figura 2. Tela inicial do utilitário Gii.

Uma vez logado no Gii, clique em “Model Generator”, presente no menu lateral à direita da página. Será aberta a página de criação de modelos para que se possa gerar automaticamente a classe ActiveRecord que tratará os dados da tabela Administrador. Confira na Figura 3.

Figura 3. Página para criação automática de modelos carregada.

No campo “Table Name” digita Administrador, clique em “Preview” e depois em “Generate”, e pronto... o modelo está criado.

Método authenticate()

Por padrão, o sistema do Yii Framework disponibiliza um sistema de login bastante básico, onde o login poderá ser feito pelos usuário e senha admin/admin ou demo/demo. Abaixo, na Listagem 2, veja o código gerado pelo Yii.

Listagem 2. Autenticação padrão do Yii Framework


  <?php
  class UserIdentity extends CUserIdentity
  {
              public function authenticate()
              {
                          $users=array(
                                     // username => password
                                     'demo'=>'demo',
                                     'admin'=>'admin',
                          );
                          if(!isset($users[$this->username]))
                                     $this->errorCode=self::ERROR_USERNAME_INVALID;
                          elseif($users[$this->username]!==$this->password)
                                     $this->errorCode=self::ERROR_PASSWORD_INVALID;
                          else
                                     $this->errorCode=self::ERROR_NONE;
                          return !$this->errorCode;
              }
  }

Nota: Para facilitar a legibilidade do código foram omitidos os comentários gerados pelo Yii.

Note que, por padrão, não é feita nenhuma conexão com o banco de dados para realizar a autenticação. Com o objetivo de validar as informações passadas, é criado o array $users, e nele é passado manualmente os usuários “registrados” no sistema. “Registrados”, pois na verdade não há nenhum local físico onde estes dados estão gravados.

Agora veja na Listagem 3 o método authenticate() realizando a autenticação através do “método convencional”, ou seja, acessando o banco de dados e validando os dados passados pelo usuário.

Listagem 3. Classe UserIdentity com o novo método authenticate(), validação com banco de dados.


  <?php
  class UserIdentity extends CUserIdentity
  {
              private $_id, $_username;
   
              public function authenticate()
              {
   
                          $record = Administrador::model()->findByAttributes(array('usuario'=>$this->username));
   
                          if($record === null){
                                     $this->errorCode = self::ERROR_USERNAME_INVALID;
                          } elseif ($record->senha !== $this->password){
                                     $this->errorCode = self::ERROR_PASSWORD_INVALID;
                          } else {
                                     $this->_id=$record->id;
                                     $this->username=$record->usuario;
                                     $this->setState('nome', $record->nome);
                                     $this->errorCode=self::ERROR_NONE;
                          }
                          return !$this->errorCode;
              }
   
              public function getId()
              {
                          return $this->_id;
              }
  }

Estrutura do novo método authenticate().

Na primeira linha é criada a variável $record, onde nela é armazenado o valor advindo do banco de dados a partir do método findByAttributes(). Este método é responsável por consultar junto ao banco todos os registros que conferirem com o array associativo passado no formato 'campo'=>valorDigitado.

Depois é feita a verificação da variável $record. Se ela for igual a null, ou seja, se a consulta solicitada não retornar resultado algum, será lançado o erro de usuário inválido. Assim como, se o usuário digitado conferir com algum registro, e a senha não, será lançado o erro de senha incorreta. Por último, se o usuário e senha fornecidos pelo usuário conferirem com a consulta, o usuário é autenticado com sucesso e seus atributos são alterados de acordo com seu registro.

Ao tentar logar com o usuário e senha “demo”, ou “admin”, será exibido o erro de login/senha inválidos. Veja na Figura 4 esta ilustração.

Autenticação com banco de dados

Figura 4. Autenticação com banco de dados.

Criando Níveis de autenticação.

A partir deste momento, a sua aplicação já possui o sistema de autenticação totalmente funcional, embora os níveis de permissão ainda não. Agora, como segunda parte deste artigo, será visto como criar níveis de permissão, possibilitando maior flexibilidade e personalização ao sistema.

Estrutura interna de manipulação.

Para manipular os níveis de restrição de cada usuário serão criadas duas classes: ManageLevel e UserLevel. A primeira classe será responsável pela visão mais abstrata dos níveis, sendo assim, ela possuirá toda a lógica de negócio que definirá. Por exemplo, se um usuário é Administrador ou Usuário Comum. Enquanto que na classe UserLevel será retornado o nível do usuário para futuras restrições de página.

Abaixo, nas Listagens 4 e 5, seguem os códigos das classes ManageLevel e UserLevel, respectivamente.

Listagem 4. Classe que possui os níveis de usuário.


  <?php 
  class ManageLevel{
        const ADMIN = 1;
        const COMUM = 2;
        
        private $niveisUsuario;
   
        public static function getLevel($nivelUsuario)
        {
            $niveisUsuario['ADMIN']          = 1;
            $niveisUsuario['COMUM']      = 2;
            return isset($niveisUsuario[$nivelUsuario]) ? $niveisUsuario[$nivelUsuario] : null;
        }
  }

O código acima é bastante autoexplicativo. Serão usadas constantes predefinidas para manipular qual nível do usuário atual logado. O método getLevel() é o responsável por verificar e retornar o nível do usuário.

Listagem 5. Código da classe UserLevel.


  <?php 
  class UserLevel extends CWebUser
  {
              protected $_model;
   
              public function isInRole($nomeRegra){
                         $usuario = $this->loadUser();
                          $nivelRegra = ManageLevel::getLevel($nomeRegra); 
                           if ($usuario && $nivelRegra)
                                return $usuario->level==$nivelRegra;
                          return false;
      }
   
              protected function loadUser(){
                          if ($this->_model === null) {
                                     $this->_model = Administrador::model()->findByPk($this->id);
                          }
                          return $this->_model;
              }
  }

Acima o método isInRole() é o principal trecho do código, é ele que retorna o nível do usuário.

*IMPORTANTE: O Yii Framework utiliza um sistema de configurações através do arquivo main.php, presente em protected/config. Para avisar ao sistema qual forma de autenticação será utilizada é necessário apontar a classe no parâmetro “user”, localizado no parâmetro “components”. Veja na Listagem 6 o trecho de código alterado para atualizar a configuração do Yii Framework.

Listagem 6. Novo trecho do arquivo de configuração.


  return array(
              // application components
              'components'=>array(
                          'user'=>array(
                                     'class'=>'application.components.UserLevel', // ← AQUI VEM A ALTERAÇÃO!
                                     // enable cookie-based authentication
                                     'allowAutoLogin'=>true,
                          ),

Nota: Para facilitar o entendimento do código foram omitidas as partes consideradas desnecessárias para este trecho.

Testando sistema de autenticação.

Antes de qualquer teste é necessário cadastrar usuários na base de dados para que os resultados sejam vistos. Confira na Listagem 7 as querys SQL.

Listagem 7. Cadastrar usuários no sistema.


  --
  
  -- Dumping data for table `Administrador`
  
  --
  
   
   
  INSERT INTO `Administrador` (`id`, `nivel`, `nome`, `email`, `usuario`, `senha`) VALUES
  
  (1, 1, 'teste', 'teste', 'teste', 'teste'),
  
  (2, 0, 'teste 2', 'teste 2', 'teste2', 'teste 2'),
  
  (3, 0, 'teste 3', 'teste 3', 'teste3', 'teste 3');

Nota: Com objetivo de não tornar este artigo demasiadamente extenso, o formulário HTML para o cadastro dos usuários no sistema será omitido.

A partir deste momento toda a estrutura de autenticação está funcionando, inclusive com os níveis de permissão de usuários. Será adotada, em toda a aplicação, uma forma de acessar o método isInRole(), responsável por identificar o nível do usuário logado atualmente. Esta forma será através da chamada Yii::app()->user->isInRole('NOME DA REGRA PASSADA'). Lembre-se que todos os níveis de autenticação podem ser facilmente manipulados na classe ManageLevel.

Como bloquear o acesso do usuário não Administrador.

Voltando ao exemplo do portal de notícias fictício “PortalNews“ , será feita a restrição da página de cadastro de notícias apenas para usuários com nível de Administrador. No controlador Noticia, restrinja a visibilidade da actionCreate() e da actionUpdate() para que apenas usuários administradores possam acessá-las. Para isso veja o código da Listagem 8.

Listagem 8. Restrição dos usuários que não são administradores.


  public function accessRules()
              {
                          return array(
                                     //CÓDIGO OMITIDO PARA MELHOR LEITURA
                                     array('allow',
                                                 'actions'=>array('create','update'),
                                                 'users'=>array(Yii::app()->user->name),
                                                 'expression'=>"Yii::app()->user->isInRole('ADMIN')",  // ← EXPRESSÃO QUE VERIFICA O NÍVEL DE ACESSO DO USUÁRIO LOGADO
                                     ),

Acesse http://SEU_ENDERECO/index.php/noticia/create e será redirecionado para a tela de login. Confira o resultado na Figura 5.

Redirecionado
para a página de Login

Figura 5. Redirecionado para a página de Login.

Primeiramente, o login será feito com um registro de nível “Comum”. Veja a seguir na Figura 6 que este usuário não poderá acessar a página de cadastro de notícias, pois não possui permissão para esta ação.

Usuário sem permissão de cadastrar notícias
no sistema

Figura 6. Usuário sem permissão de cadastrar notícias no sistema.

Agora a mesma página será acessada por um usuário cujo registro é de nível Administrador. Note que a página de cadastro de notícias será carregada normalmente, pois este nível de usuário possui permissão para acessá-la. Confira na Figura 7.

Usuário com
permissão de cadastrar notícias no sistema

Figura 7. Usuário com permissão de cadastrar notícias no sistema.

Neste artigo foi tratado a forma com a qual o Yii Framework autentica os usuários logados, além da implementação de um sistema customizado de autenticação por nível de permissão.