domingo, 12 de fevereiro de 2012

Essa é minha casa ? :: Sistema simples de login com Zend

Esse deve ser o que deixa boa parte dos programadores de Zend com água na boca.
Um sistema de login, é uma das maiores nescessidade quando se colocar seu apĺicativo online e não quer ver fulano mechendo na sua área administrativa que tanto tempo levou pra fazer. Ou quando cria um sistema em que seus usuários fazem coisas escondidas que só eles podem saber ... hehehe
De qualquer forma, um sistema de login é o que vão ter agora.
Primeiro, temo de criar a tabela de usuarios no banco de dados:

CREATE TABLE IF NOT EXISTS 'usuarios' (
  'id' int(11) NOT NULL AUTO_INCREMENT,
  'login' varchar(255) NOT NULL,
  'senha' varchar(255) NOT NULL
  PRIMARY KEY ('id')
);

Simples de entender né ?

A partir disso, entre no seu terminal, vá para a pasta de seu aplicativo em Zend, e criemos o formulario de login para colocar na página inicial ( controller index e action index ):

$ zf create form login

Abra o arquivo 'application/forms/Login.php' gerado, e coloque as linhas

class Application_Form_Login extends Zend_Form {

    public function init(){

        // Define a página do action, no caso, o proprio action index de login.
        setAction('index');
 
        // Método de envio do form.
        $this->setMethod('post');
         
        // Nome de usuário.
        $this->addElement('text', 'login', array( 'label'    => 'Login', 
                             'required' => 'true',            
               'validator' => array('noempty')  
                                                )
                         );
 
        // Senha de usuário.
        $this->addElement('password', 'senha', array( 'label'    => 'Senha',
                   'required' => 'true',
                   'validator' => array('noempty')
                                                    )
                         );
        
        // Botão de submissão.
        $this->addElement('submit', 'submit', array('label' => 'Entrar') );
     
    }

}


E agora, no seu controller 'controllers/IndexController.php' escreva as linhas no action 'indexAction'


public function indexAction(){
     
       // Cria o objeto de formulário.
     $loginForm = new Application_Form_Login();

     // É verificado se existem dados enviados via post ( caso de tentativa de login ).

     // Verifica se existem dados enviados via POST.
     if( $this->getRequest()->isPost()  ) {
        
                // Salva os dados enviados via post no array '$data'.
      $data = $this->getRequest()->getPost() ;
 
         // Verifica se os dados são válidos.
         if( $loginForm->isValid($data)  ) {

          // Pega o nome de usuário e a senha enviados pelo POST.
          $login = $loginForm->getValue('login');
                  $pass  = $loginForm->getValue('senha');
                  
             ///////////////////////////////////////////////////////////
             // Pega as informações do adaptador do banco de dados.
             $dbAdapter = Zend_Db_Table::getDefaultAdapter();
                          
             // Inicia o adaptador Zend_Auth para banco de dados.
                // É definido a tabela do db e os campos que serão usados
                // para comparar com os campos de login. 
             $authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
             $authAdapter->setTableName('usuarios')
                     ->setIdentityColumn('login')
                    ->setCredentialColumn('senha')
                     ->setCredentialTreatment('MD5(?)');
                // Aqui, a senha é transformada num hash md5 e só então
                // comparado com a senha registrada no db ( que está em md5 também ).
                // Se você usa SHA1 ou outra codificação, é aqui que vocÊ deve declarar.
                //////////////////////////////////////////////////////////
                 
                ///////////////////////////////////////////////////////////
                // Agora, é comparado os dados digitados com os registrados.
             $authAdapter->setIdentity($login)->setCredential($pass);

                // Pega a instância atual do Zend_Auth.
                $auth = Zend_Auth::getInstance();
                
                // Pega o resultado da comparação dos dados enviados com os registrados.
                $result = $auth->authenticate($authAdapter);
                
                // Caso o resultado seja positivo, o login é efetuado.
                if( $result->isValid() ) {                
                                 
                 // Pega o nome do usuário.
                 $user = $authAdapter->getResultRowObject();
                 
                 // Salva o nome do usuário para uso na sessão.
                 $auth->getStorage()->write($user);
                 
                 // Redireciona para a primeira página após o login.
                 $this->_redirect("index/primeirapagina" );
              
                }
                // Caso não seja positivo ...
                else{
                 
                 // Caso o usuário não esteja registrado, é mostrado uma mensagem mostrando o fato.
                   $this->view->messages = "Não foi possível realizar o login.";
                   
                   // Reimprime o formulário com os dados já digitados.
                   $this->view->loginForm = $loginForm->populate($data);

                }
                ///////////////////////////////////////////////////////////
                                           
           }
           // Caso os dados não foram digitados corretamente, é reimprimido o formulário com os dados para correção.
           else $this->view->loginForm = $loginForm->populate($data);
              
     }
     // Imprime por default o formulário na entrada do site.
     else $this->view->loginForm = $loginForm;
     
}

E a partir desse ponto, você já têm um sistema de login funcional, brinque um pouco com ele para er se está tudo certo, porque agora vamos para a real utilidade de um sistema de login.

Pois bem, se você perceber, ainda pode navegar pelas páginas de sua aplicação Zend sem precisar realizar o login ( digite na url qualquer endereço dela para ver que entra numa boa ainda ).
E a não ser que você tenha um motivo especial para fazer um sistema de login que deixe tudo aberto, o que queremos é impedir o acesso a pessoas não logadas, não ?
Pois bem, a "tranca da porta" de nossa aplicação são essas duas linhas:

// Pega a instância atual do Zend_Auth.
$auth = Zend_Auth::getInstance();
        
// Verifica se o usuário está logado.
if( $auth->hasIdentity() ) { <faz alguma coisa> }

Nessas duas linhas, você verifica se o usuário está logado, se não está, geralmente você o envia para a página inicial, assim

// Pega a instância atual do Zend_Auth.
$auth = Zend_Auth::getInstance();
        
// Verifica se o usuário está logado.
if( $auth->hasIdentity() ) { <faz alguma coisa> }
else $this->_redirect('index/paginainicial');

Essas linhas você pode colocar no action 'init()' de seus controllers que quer restringir acesso - ou em algum action em particular, ou mesmo nas próprias views -  e já terá garantido a um pouco de segurança a sua aplicação.

É isso ai. Não, não acabou. Ainda falta uma coisinha.

Quando você se loga, sua identificação no aplicativo fica salvo na instância do Zend_Auth, e voltar para a página inicial simplesmente não resolve isso, o que pode ser perigoso, pois o usuario se loga, navega, sai, mas seu login continua lá para um outro safado sem vergonha usar brincar de graça na sua aplicação.

Para impedir isso é bem simples também. Criemos uma action no 'IndexController.php' com o nome de 'logoutAction'

$ zf create action logout

e acrescente as seguintes linhas

public function logoutAction(){
     
      // Apaga da instância do Zend Auth a identificação no sistema.
      Zend_Auth::getInstance()->clearIdentity();
    
      // Redireciona para a página inicial do site.
      $this->_helper->redirector('index');
        
}

E assim, no seu layout, crie um link escrito 'logout' que aponte para esse action


<?php
$logoutUrl = $this->view->url(array('controller'=>'index', 'action'=>'logout'), null, true);
            
// Imprime a mensagem de boas vindas com o nome do usuário e o link para logout.
print "<a href=".$logoutUrl.">Logout</a>";
?>

Assim, para sair, basta clicar no link 'logout', e a saida do usuário ficará limpa.

Agora é só se divertir montando seus aplicativos, que atgora terão a devida segurança e privacidade que nescessitam. Até a próxima.






Referências:

- Zend Auth : http://framework.zend.com/manual/en/zend.auth.introduction.html

- Autenticação com Zend Framework : http://fernandomantoan.com/frameworks/zend-framework/autenticacao-com-zend-framework/

Um comentário:

  1. Cara.
    Muito legal o site!
    Não consegui fazer o exemplo pois sempre nesta linha $result = $auth->authenticate($authAdapter); dá pau e não é validado as informações de login.
    Eu tenho uma tabela com 9 colunas sendo que nestas 9 tem-se o login e a senha. Mapeei corretamente, a função chama correto e até consegue o registro certo mas em algum ponto ele retorna o $result com cógico -3 e a mensagem Supplied credential is invalid.

    Pode me ajudar?
    Obrigado.

    ResponderExcluir