nov 08

Autenticação Através de Banco de Dados com Zend_Auth

Autenticação, Auth, Login, PHP, Programação, Zend Framework, Zend_Auth 4 Comentários Zend Framework

Boa parte das aplicações desenvolvidas para a web tem pelo menos uma pequena área de acesso restrito, essa área pode restringir o acesso a determinado conteúdo somente para usuários cadastrados ou pode até mesmo ser uma área de administração dessa aplicação, onde o acesso não autorizado poderia trazer mais prejuízos, por isso, é sempre importante desenvolver uma forma segura de verificar as credencias do usuário e isso fica ainda melhor se além de segura essa forma puder ser tão simples como a solução disponível no Zend Framework que será apresentada nesse artigo.

A Classe Zend_Auth

A classe Zend_Auth do Zend Framework é responsável por cuidar de todo o processo de autenticação e armazenamento da seção de login do usuário, deixando muito mais simples o trabalho de verificação das credenciais de acesso e permitindo a utilização de diversos modo de verificação, incluindo verificação de identidade através do banco de dados, através do protocolo HTTP e até mesmo através de serviços como OpenID. Além disso ela pode ser extendida para realizar a verificação por qualquer outro modo que não esteja disponível nativamente. Nesse artigo apenas o método de autenticação através do banco de dados será apresentado, mas você pode conferir a Documentação Oficial da Classe Zend_Auth caso precise realizar a autenticação através de outro método.

Autenticação Através de Banco de Dados

Tabela de Usuários

Tabela de Usuários

Para realizar a autenticação de usuário através do banco de dados é preciso ter uma tabela nesse banco com pelo menos duas colunas, o login e a senha, para critério de exemplo nesse artigo vou adicionar também o nome completo do usuário, seu e-mail, além disso o campo de senha será criptografado usando MD5 (lembrando que o uso de Md5 para armazenar senhas não é recomendado pois é um algorítimo com grande facilidade de quebra, nesse caso usarei apenas como exemplo). O diagrama ao lado ilustra o banco de dados que deverá ser criado para esse exemplo e abaixo transcrevo o código SQL desse banco:

CREATE TABLE `User` (
	id    int(11) NOT NULL AUTO_INCREMENT,
	nome  varchar(255) NOT NULL,
	mail  varchar(255) NOT NULL,
	login varchar(255) NOT NULL,
	pass  varchar(255) NOT NULL,
	PRIMARY KEY (id)
);

O Formulário

Para criar uma ferramenta de login precisamos criar um formulário por onde o usuário irá informar seus dados para que esses sejam verificados.

<?php

class Form_Login extends Zend_Form
{
	public function init()
	{
		$login = new Zend_Form_Element_Text('login');
		$login->setLabel('Login do Usuario')
			->setRequired(true)
			->addFilter('StripTags')
			->addFilter('StringTrim');

		$senha = new Zend_Form_Element_Password('senha');
		$senha->setLabel('Senha do Usuario')
			->setRequired(true)
			->addFilter('StripTags')
			->addFilter('StringTrim');

		$submit = new Zend_Form_Element_Submit('Entrar');
		$this->addElements(array($login, $senha, $submit));
	}
}

O formulário acima contem apenas dois campos, o campo de login e o campo de senha, além é claro do botão que enviará esse formulário para que seus dados sejam processados, as informações sobre método de envio (GET ou POST) foram omitidas, mas é sempre bom lembrar que é altamente recomendável passar dados de login apenas por POST e nunca por GET já que no segundo caso eles ficam visíveis na URL.

O Controller

Praticamente toda a verificação de login nesse exemplo será realizada no Controller, por isso essa parte necessita de um pouco mais de atenção, abaixo segue o código desse controller que será devidamente explicado abaixo.

public function loginAction(){
	if(Zend_Auth::getInstance()->hasIdentity()){
		$this->_redirect('index');
	}else{
		$this->view->form = new Form_Login();

		if($this->getRequest()->isPost() and $this->view->form->isValid($_POST)){
			$values = $this->view->form->getValues();

			$dbAdapter = Zend_Db_Table::getDefaultAdapter();
			$adapter = new Zend_Auth_Adapter_DbTable($dbAdapter);

			$adapter->setTableName('User')
				->setIdentityColumn('login')
				->setCredentialColumn('pass')
				->setIdentity($values['usuario'])
				->setCredential($values['senha'])
				->setCredentialTreatment('MD5(?)');;

			$auth = Zend_Auth::getInstance();
			$result = $auth->authenticate($adapter);

			if ($result->isValid()) {
				$this->_redirect('index');
			}else{
				$this->view->form->setDescription('Usuário ou Senha Inválidos');
			}
		}
	}
}

Uma Action de Login (loginAction) está sendo criada e logo no início dessa Action está sendo chamado um método estático da classe Zend_Auth para verificar se o usuário já está logado, caso ele já esteja ele é direcionado para a página inicial, caso não esteja o formulário criado anteriormente é instanciado e armazenado na variável $this->view->form, ou seja está sendo armazenado em uma variável e passado a visão ao mesmo tempo.

Logo em seguida verificamos se existe uma requisição POST a essa ação e caso exista se o valores passados por essa requisição são válidos de acordo com os parâmetros de validação do formulário, nesse ponto cabe uma observação, caso a requisição não seja do tipo POST ou os valores não forem válidos o formulário será exibido na tela, ou seja, se o visitante ainda não envio nenhum dado para o formulário ou se esses dados estão errados (apenas do ponto de vista de validação de dados, não de login) ele será encaminhado ao formulário para enviar essas informações ou corrigir as informadas anteriormente.

Caso a requisição seja do tipo POST e os valores válidos chegou a hora de verificar se as credenciais estão corretas. A primeira coisa a ser feita é requisitar o adaptador padrão do banco de dados através do método Zend_Db_Table::getDefaultAdapter() e armazená-lo em uma variável, já que vamos precisar dele mais tarde, caso não exista um adaptador padrão previamente configurado será necessário iniciar uma conexão ao banco de dados. Em seguida é criada uma instancia da classe Zend_Auth_Adapter_DbTable passando como parâmetro o adaptador do banco citado anteriormente, e essa instância é armazenada em uma variável.

O próximo passo e passar as informações sobre os dados que serão usados por essa classe através dos métodos chamados logo em seguida. O método setTableName() recebe o nome da tabela de usuários no banco de dados, o método setIdentityColumn() recebe o nome da coluna do banco de dados onde está armazenada a informação de nome de usuário, setCredentialColumm por sua vez recebe o nome da coluna onde está armazenada a senha, os métodos setIdentity e setCredential recebem respectivamente os valores de login e senha passados pelo usuário e por fim o método setCredentialTreatment() recebe a informação sobre o tratamento que será fornecido a senha, nesse caso estamos utilizando a função md5() para criptografar essa senha.

Por fim requisitamos a instância da classe Zend_Auth e chamamos o método authenticate passando como parâmetro a instancia da classe Zend_Auth_Adapter_DbTable já com as informações armazenadas, se o retorno desse método for TRUE redirecionamos o usuário a página inicial se for FALSE incluimos uma descrição ao formulário com as informações de que o login e senha estão incorretos e enviamos o visitante de volta ao formulário para que ele preencha corretamente as informações.

A View

A View nesse caso só tem mesmo que exibir o formulário da seguinte fora:

<h2>Acesso Restrito a Usuários Cadastrados</h2>
<?php echo $this->form; ?>

Armazenando Informações na Seção de Login

Através do método apresentado anteriormente foi possível verificar as credenciais do usuário que estava realizando o login e criar a seção de login do mesmo, porém nessa seção o único dado que foi armazenado foi o nome do usuário, porém as vezes é preciso que mais dados que estejam disponíveis na tabela do banco de dados também sejam armazenados, para isso basta realizar apenas uma pequena alteração no controller que ficará da seguinte forma:

public function loginAction(){
	if(Zend_Auth::getInstance()->hasIdentity()){
		$this->_redirect('index');
	}else{
		$this->view->form = new Form_Login();

		if($this->getRequest()->isPost() and $this->view->form->isValid($_POST)){
			$values = $this->view->form->getValues();

			$dbAdapter = Zend_Db_Table::getDefaultAdapter();
			$adapter = new Zend_Auth_Adapter_DbTable($dbAdapter);

			$adapter->setTableName('User')
				->setIdentityColumn('login')
				->setCredentialColumn('pass')
				->setIdentity($values['usuario'])
				->setCredential($values['senha'])
				->setCredentialTreatment('MD5(?)');;

			$auth = Zend_Auth::getInstance();
			$result = $auth->authenticate($adapter);

			if ($result->isValid()) {
				$storage = $auth->getStorage();
				$storage->write($adapter->getResultRowObject(null,'pass'));

				$this->_redirect('index');
			}else{
				$this->view->form->setDescription('Usuário ou Senha Inválidos');
			}
		}
	}
}

Logo antes de redirecionar o usuário para a página inicial foi chamado o método getStorage() da classe Zend_Auth e em seguida chamado o método write que recebe como parâmetro o retorno do método getResultRowObjet() que por sua vez pode receber como primeiro parâmetro uma lista de colunas do banco de dados que serão armazenadas (nesse caso foi passado null, que fará com que todas as colunas sejam armazenadas) e como segundo parâmetro uma lista das colunas que não serão armazenadas (nesse caso passamos o nome da coluna que contem a senha), ou seja, todas as colunas exceto a que contém a senha serão armazenadas, depois de ter realizado esse processo basta realizar o seguinte procedimento para exibir as informações da seção de login:

echo Zend_Auth::getInstance()->getIdentity(); //Retorna o Login do Usuário mesmo que um Storage não tenha sido criado
echo Zend_Auth::getInstance()->getIdentity()->nome; //Retorna o Nome do Usuário
echo Zend_Auth::getInstance()->getIdentity()->email; //Retorna o E-mail do Usuário

Conclusão

Através da classe apresentada nesse artigo é possível realizar de forma fácil e segura a autenticação do usuário através de diversos meios, aqui apenas um desses meios foi mostrado mas tenha certeza de que com pouca mudança no que foi apresentado é possível se adaptar a qualquer que seja a sua necessidade.

4 comentários sobre “Autenticação Através de Banco de Dados com Zend_Auth”

  1. Thiago disse:

    Nao da certo aqui comigo…infelizmente…

    • Paulo Eduardo disse:

      Ola Thiago, tudo bem?

      Compartilhe conosco qual o problema que você teve com a autenticação usando Zend_Framework, obrigado.

      • Talvez o problema dele tenha sido o mesmo do meu.
        No action login, eu precisei trocar a linha
        $this->view->form = new Form_Login(); por $this->view->form = new Application_Form_Login();. Isso resolveu meu problema.

        • Paulo Eduardo disse:

          Ola Luiz, tudo bem?

          Isso pode variar muito de acordo com a sua configuração de autoloading do framework e de acordo com o diretório onde você está armazenando os arquivos do formulario, no meu caso o autoloading está configurado para que eu não tenha que informar o diretório application sempre, por isso na maioria dos artigos aqui do blog os formulários estão sendo instanciados dessa forma, mas é realmente uma questão de preferência mesmo.

          O que sei é que na versão 2.0 do framework toda a classe de autoloading deve ser reescrita e isso deve facilitar muito o trabalho de instanciamento de classes e injeção de pacotes.

Deixe um Comentário