Back-End

22 set, 2010

Criando uma biblioteca para controle de acesso por usuário aplicada a classes e métodos com o CodeIgniter

Publicidade

As aplicações PHP estão se tornando a
cada dia mais complexas, aplicações de uso comercial, acadêmico e
das mais diversas finalidades fazem necessário um controle mais
apurado de acesso.

No CodeIgniter, obrigatoriamente estamos
sempre acessando uma classe e um método de um controlador. Dessa
forma, é possível mapear todas as possíveis ações e/ou caminhos
disponíveis em uma aplicação e adicionar o controle de acesso aos
métodos que desejamos controlar.

Desenvolvi uma biblioteca (librarie) para
controlar o acesso dos usuários, o funcionamento é o seguinte.

Em uma tabela no banco de dados
(sys_metodos),
ficam guardados os nomes de classe e os métodos, mapeando todos os
possíveis caminhos e em outra (sys_permissoes)
ficam as ids dos usuários com os respectivos métodos a que eles têm
acesso. Essa segunda tabela está relacionada à tabela de cadastro de
usuários (tb_usuarios).


Figura 1 – Estrutura das
tabelas necessárias ao sistema de autenticação

Seria bastante trabalhoso ter que popular a
tabela de métodos manualmente, ou criar um Admin para ela, dessa
forma, foi incluída uma rotina na própria biblioteca para que
quando um método invocado por ela não for encontrado na tabela
sys_metodos ele seja automaticamente criado. Dessa forma, na primeira
vez em que um método for acessado, ninguém terá permissão de acesso,
assim, será necessário parametrizar o sistema uma única vez no
primeiro acesso. Depois poderá se construir uma área de
administração para varrer a tabela de métodos e adicionar ou
remover as permissões dos usuários.

O CodeIgniter provê uma maneira de
checarmos “onde estamos”, ou seja, em que classe e em que método.

Para verificar o nome da classe, utilize a
seguinte linha de código:

$this->router->class

E para recuperar o nome do método utilize:

$this->router->method

Dessa forma, podemos passar para a
biblioteca o caminho completo de onde estamos da seguinte forma:

$this->auth->check_logged($this->router->class , $this->router->method);

Sendo auth o nome da biblioteca e check_logged o método que estamos acessando na biblioteca.
Como essa biblioteca estará sendo acessada em muitas classes e métodos,
é preferível carregar no autoload para que ela esteja sempre disponível
em qualquer parte da aplicação.

Para proteger um método, basta incluir
a linha de código conforme mostrado na primeira linha do método da
seguinte forma.


class AreaRestrita extends Controller {

function __construct(){

parent::Controller();

}

function index(){

$this->auth->check_logged($this->router->class , $this->router->method);

}

}

?>

Vejamos então como fica o código fonte
da biblioteca. Salve o código-fonte a seguir com o nome de arquivo auth.php
na pasta system/application/libraries.

      
class Auth

{

private $ci;

public function __construct(){

$this->ci = &get_instance();

}

function check_logged($classe,$metodo)

{

/*

* Criando uma instância do CodeIgniter para poder acessar

* banco de dados, sessionns, models, etc...

*/

$this->CI =& get_instance();



/**

* Buscando a classe e metodo da tabela sys_metodos

*/

$array = array('classe' => $classe, 'metodo' => $metodo);

$this->CI->db->where($array);

$query = $this->CI->db->get('sys_metodos');

$result = $query->result();

// Se este metodo ainda não existir na tabela sera cadastrado

if(count($result)==0){

$data = array(

'classe' => $classe ,

'metodo' => $metodo ,

'apelido' => $classe . '/' . $metodo,

'privado' => 1

);

$this->CI->db->insert('sys_metodos', $data);

redirect(base_url(). $classe . '/' . $metodo, 'refresh');

}

//Se ja existir tras as informacoes de publico ou privado

else{

if($result[0]->privado==0){

// Escapa da validacao e mostra o metodo.

return false;

}

else{

// Se for privado, verifica o login

$nome = $this->ci->session->userdata('nome');

$logged_in = $this->ci->session->userdata('logged_in');

$data = $this->ci->session->userdata('data');

$email = $this->ci->session->userdata('email');

$id_usuario = $this->ci->session->userdata('id_usuario');



$id_sys_metodos = $result[0]->id;

// Se o usuario estiver logado vai verificar se tem permissao na tabela.

if($nome && $logged_in && $id_usuario){



$array = array('id_metodo' => $id_sys_metodos, 'id_usuario' => $id_usuario);

$this->CI->db->where($array);

$query2 = $this->CI->db->get('sys_permissoes');

$result2 = $query2->result();

// Se não vier nenhum resultado da consulta, manda para página de

// usuario sem permissão.

if(count($result2)==0){

redirect(base_url().'home/sempermissao', 'refresh');

}

else{

return true;

}

}

// Se não estiver logado, sera redirecionado para o login.

else{

redirect(base_url().'home/login', 'refresh');

}

}

}

}



/**

* Método auxiliar para autenticar entradas em menu.

* Não faz parte do plugin como um todo.

*/

function check_menu($classe,$metodo){

$this->CI =& get_instance();

$sql = "SELECT SQL_CACHE

count(sys_permissoes.id) as found

FROM

sys_permissoes

INNER JOIN sys_metodos

ON sys_metodos.id = sys_permissoes.id_metodo

WHERE id_usuario = '" . $this->ci->session->userdata('id_usuario') . "'

AND classe = '" . $classe . "'

AND metodo = '" . $metodo . "'";

$query = $this->CI->db->query($sql);

$result = $query->result();

return $result[0]->found;

}

}

Note que a biblioteca
se encarrega de inserir os dados de métodos e classes que ainda não
estejam cadastrados na tabela sys_metodos.

Quando um usuário tentar
acessar uma área do website ou sistema em que ele não tenha privilégios, ele será redirecionado para uma página específica.

redirect(base_url().'home/sempermissao','refresh'); 

E que quando ele não
estiver logado, será redirecionado para a página de login.

redirect(base_url().'home/login','refresh');

Incluí