Mais um blog inútil.

Fevereiro 5, 2008

Conceito dum sistema de permissoes

Filed under: Coding,Useless — armorfist @ 13:10

Oix caros blogfags.
Hoje vou mostrar aqui um método de gestão de permissões com base de dados. Não vou dar nada em concreto, apenas a teoria.
Imaginemos que temos o saite separado em módulos, e queremos um sistema de permissões que suporte grupos que depois estarão associados a utilizadores.

Carreguem ali naquele botão MOAR para verem o resto.


Temos o módulo "noticias", "blogs", "morte" e "lulz". Grupo chamado "Admin" tem acesso ao modulo de "noticias", "blogs", "morte" e "lulz" enquanto o grupo "Doslulz" apenas tem acesso ao modulo "lulz" e o grupo "Damorte" apenas tem acesso ao modulo "morte". Cada utilizador poderá fazer parte de 1 ou mais grupos, sendo que se fizer parte do grupo "Admin" terá acesso aos módulos "noticias", "blogs", "morte" e "lulz", se fizer parte do grupo "Doslulz" e o grupo "Damorte" terá acesso aos módulos "lulz" e "morte" respectivamente. Uma das maneiras de fazer isto com base de dados é ter 3 tabelas, uma para guardar os módulos, outra para guardar os grupos, e outra para guardar os utilizadores que pertencem aos grupos.

Exemplo:
Tabela Modulos:
id_modulo
nome

Tabela Grupos:
id_grupo
nome
acessos

Tabela Membros_do_grupo:
id_membro
grupos

Existe uma operação muito fofa que se chama "Bitwise AND" representado em sql pelo operador "&" que funciona da seguinte forma:

Em binário: 2 = 10, 4 = 100, 6 = 110
O bit a 1 do 2 também esta a 1 no 6, logo 2 está contido em 6

Outro exemplo:
Em binário: 32 = 100000, 8 = 1000, 32+8 = 40 = 101000
O bit a 1 de 32 também está a 1 no 40, e o bit a 1 de 8 também está a 1 em 40, logo estão ambos contidos em 40.

(Obrigado Dcoder pela explicação)

Desta forma, usamos potências de 2 para os ID's dos módulos e grupos, e guardamos a soma dos ID's na coluna "acessos" e "grupos" da tabela grupos e membros respectivamente.

 

Exemplo:

Tabela Modulos:
---
id_modulo = 2
nome = "noticias"
---
id_modulo = 4
nome = "blogs"
---
id_modulo = 8
nome = "morte"
---
id_modulo = 16
nome = "lulz"
---

Tabela Grupos:
---
id_grupo = 2
nome = "Admin"
acessos = 30 (2+4+8+16)
---
id_grupo = 4
nome = "Doslulz"
acessos = 16
---
id_grupo = 8
nome = "Damorte"
acessos = 8

Tabela Membros_do_grupo:
id_membro = 1
grupos = 2 (tem acesso ao grupo "Admin")
---
id_membro = 2
grupos = 12 (4+8 tem acesso ao grupo "Doslulz" e "Damorte")

De seguida poderemos fazer uma query do estilo:

SELECT Modulos.nome,Grupos.nome
FROM Membros_do_grupo
LEFT JOIN Grupos
ON Grupos.id_grupo & Membros_do_grupo.grupos
LEFT JOIN Modulos
ON Modulos.id_modulo & Grupos.acessos
WHERE Membros_do_grupo.id_membro = 2

Esta query iria dar o resultado que o utilizador id 2 pertencia ao grupo "Doslulz" e "Damorte" e consequentemente tinha acesso ao modulo "lulz" e "morte".

 

Isto é tudo muito bonito, mas o problema com as potencias é que crescem exponencialmente, como podem observar no gráfico abaixo.

 

Grafico exponencial

Gráfico da função exponencial base 2

 

Para terem uma ideia, se tivermos 30 módulos, o modulo numero 30 irá ter o ID 2^30 que é nada mais nada menos que 1073741824. Isto sem contar que teremos de somar o ID de todos os módulos para guardar na coluna acessos da tabela grupos, que se fossem 30, poderia chegar ao número 2147483646 (ITS OVER NINE THOUSAAAAAAAAND).
È ai que entram os logaritmos. Para quem não tem mais que o 9º ano, um logaritmo de x com base b dá o numero pelo qual teríamos de elevar b de forma a dar x, ou seja: y = logb(x) é equivalente a x=b^y. Ainda não perceberam? Ok. log2(16) = 4 é equivalente a 2^4 = 16. Não é muito difícil.
Se formos ver o gráfico do logaritmo vemos que ele cresce mais lentamente que o da exponencial:

 

Gráfico logaritmo
Gráfico da função logarítmica, vermelho representa a base e, verde representa a base 10 e roxo representa a base 1.7

Então em vez de guardar o ID do módulo em forma de potencia de 2, guardamos o logaritmo base 2 desse numero:

Tabela Modulos:
---
id_modulo = 1 (log2(2))
nome = "noticias"
---
id_modulo = 2 (log2(4))
nome = "blogs"
---
id_modulo = 3 (log2(8))
nome = "morte"
---
id_modulo = 4 (log2(16))
nome = "lulz"
---

Para fazer os grupos, teremos de fazer a soma dos ID's dos módulos em formato de potencia de 2, mas desta vez, depois da soma, aplicamos aqui também a função logarítmica base 2, reduzindo drasticamente o numero:

Tabela Grupos:
---
id_grupo = 1 (log2(2))
nome = "Admin"
acessos = 4.907 (arredondado para cima a 3 casas decimais) (2+4+8+16 = 30 -> log2(30) = 4.907)
---
id_grupo = 4 (log2(16))
nome = "Doslulz"
acessos = 4 (log2(16))
---
id_grupo = 3 (log2(8))
nome = "Damorte"
acessos = 3 (log2(8))

Tabela Membros_do_grupo:
id_membro = 1
grupos = 1 (log2(2))
---
id_membro = 2
grupos = 3.585 (4+8 = 12 tem acesso ao grupo "Doslulz" e "Damorte" -> log2(12) = 3.585)

E finalmente a query que viram em cima um pouco modificada para este sistema funcionar:

SELECT Modulos.nome,Grupos.nome
FROM Membros_do_grupo
LEFT JOIN Grupos
ON POW(2,Grupos.id_grupo) & CEILING(POW(2,Membros_do_grupo.grupos))
LEFT JOIN Modulos
ON POW(2,Modulos.id_modulo) & CEILING(POW(2,Grupos.acessos))
WHERE Membros_do_grupo.id_membro = 2

Os valores guardados na base de dados ficam drasticamente reduzidos, e a conversão é feita na própria query através da função POW(x,y), que eleva x a y. CEILING é para arredondar o numero para cima para as colunas grupos e acessos darem números inteiros. Apesar de parecer que irá ter perdas de performance em questão de processamento, esta query é tão ou mais rápida a executar que uma query simples de SELECT. Por exemplo com 10 módulos, demora cerca de 0.004 segundos a executar, o que é insignificante.

Fim. Espero que percebam e que isto seja útil. (ao contrario dos posts do Dcoder, que ninguém percebe nada, e tudo é inútil) (amo-te mt Dcoder)

Bjs

Copyright (C) 2008  Armorfist

This information is free: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This information is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this article.  If not, see <http://www.gnu.org/licenses/>.

4 comentários a “Conceito dum sistema de permissoes”

  1. devnull diz:

    Valeu a pena esperar, já tava em pulgas para ler o teu postzinho
    . amo-te

  2. Lulz diz:

    Completamente inútil. Ja ouviste falar em ACL's ?

  3. Armorfist diz:

    Oix Lulz,
    Isto é uma forma de fazeres store às permissões em base de dados, podes usar o modelo ACL se quiseres juntamente com este sistema. Se tens outra ideia acerca disso gostaria de saber pois estou a criar um sistema de permissões e ideias são sempre bem vindas. (quem és btw?)

    Jokas

Comentar

widgeon
widgeon
widgeon
widgeon