Dúvida com permissões

Boa tarde pessoal

Estou trabalhando em um sistema que, inicialmente, não é MUITO grande, mas tem uma complexidade considerável, porém, pode ir a crescer bastante com a implementação de novos módulos.

Esse sistema será multiusuário, e cada usuário só poderá acessar as áreas as quais tiver permissão.

Uma forma de implementar isso seria, na entidade Usuario, ter vários atributos boolenos, tipo:

private boolean gerenciaUsuarios;
private boolean geraRelatorioMensal;

Isso funciona, mas como o sistema tende a crescer, sendo adicionados novos módulos e funcionalidades, quando colocasse uma funcionalidade nova, teria de alterar a classe Usuario do modelo, e o banco de dados, colocando mais um boolean para aquela função. Por exemplo, se implementar uma função para gerarRelatorioAnual, teria de alterar o banco de dados e adicionar na classe Usuario:

private boolean geraRelatorioAnual;

Uma solução que encontrei, baseada na apresentada em uma apostila da Caelum, foi de implementar uma anotação Role, mas não segui a implementação utilizada lá, por diferenças de requisito mesmo, já que não tenho grupos de usuários, mas sim funções específicas.

Estou implementando da seguinte maneira: minha classe Usuario tem um atributo role:

private String role;

Nesse atributo, coloco todas as Strings das permissões do usuário, separando por espaço, por exemplo:

private String role = "gerenciaUsuario geraRelatorioAnual geraRelatorioMensal";

No meu método de geração de relatórios mensais, por exemplo, anotei da seguinte maneira:

public class Relatorio(){
     
     @Role("geraRelatorioMensal")
     public void mensal(){
          ...
     }

}

Estou usando VRaptor, então aproveito o conceito de Interceptor. Quando recebo uma requisição, pego a lógica requisitada e verifico a anotação de Role que ela possui, no caso, geraRelatorioMensal. Ai verifico se no atributo role do usuario que esta tentando acessar, contem a String geraRelatorioMensal.

Nas telas, o ítem do menu também só deve aparecer para quem tiver a permissão. Para isso uso o seguinte:

<c:if test="${fn:contains(usuario.role, ' geraRelatorioMensal ') || fn:contains(usuario.role, ' admin ')}">
     //crio o menu
</c:if>

Dessa forma, ao colocar uma nova funcionalidade no sistema, eu teria apenas de escrever no role dos usuários que irão acessá-la, mas não precisaria mecher na estrutura do banco e nas classes do modelo. Por outro lado, isso pode gerar uma String enorme, guardada na minha sessão. Uma opção foi criar um role admin, que pode fazer tudo, ai não precisa colocar todas Strings, mas se não puder fazer alguma coisa, uma única que seja, já teria que escrever todas as outras permissões.

Queria ouvir opiniões a respeito da solução que estou usando, dicas de qual seria a melhor opção e conhecer outras formas que tenham utilizado no controle de acesso.

Desde já agradeço a todos.

Abraço

Cara eu estou desenvolvendo um sistema tbm… estou utilizando o Vraptor tbm e estou fazendo parecido com o seu
dei uma olhada no JAAS ele me pareceu pouco flexivel e muito trabalhoso , não sei se ha uma maneira mais “elegante” de fazer isso mais é assim que estou fazendo !
:smiley:

Isso pode ser bom ou ruim né… porque ou é uma solução adequada, ou simplesmente estamos fazendo besteira juntos rs.

Abraço

UAHUHAUA é…
mais você ja deu uma olhada nas soluções prontas para nivel de acesso?
são todas (ou pelo menos as que eu vi) muito complexas e talz.

obs: espero que estejamos fazendo certo kk

Sim, dei uma olhada.

As que vi, ou são muito complexas ou dividem por grupos de usuários… e no meu caso, como não são grupos, ja que cada usuário pode ter permissões únicas, elas não atendem.

Espero que isso que estamos fazendo de certo. Minha preocupação é quanto a uma String muito grande na sessão do usuário.

O interceptador poderia fazer uma query na base perguntando se o usuário tem o Role especificado ou se ele pertence a algum grupo que tenha esse role.

Se quiser fazer um cache local pra não ficar fazendo a query toda hora, poderia colocar um atributo Set ao carregar o usuário, e perguntar para ele mesmo se ele tem o tal Role com usuario.hasRole(Role), implementado com um contains do Set.

Nesse caso não mudaria muito se o hasRole utilizasse o contains do String né, que é como faço hoje, ou mudaria?

paulohrl, voce poderia usar um Properties contendo os nomes das permissões e o valor. Não sei, mas também tenho dúvidas quanto a isso ai. XD
valeu.

Desculpa demora em responder…

Um properties? Não entendi como seria, já que a aplicação é web e multí-usuário. Seria o properties só pra ver se determinada string da acesso a determinada função?

Galera, to usando o esquema que falei, de uma String de role. É muito ruim? Imaginei como outra solução, criar uma entidade permissão, e meu usuário teria uma lista d epermissão… Minha classe permissão seria bem simples:

public class Permissao{
   String permissao;
   Usuario usuario;
}

Para cada permissão que o cara tivesse seria uma nova linha no banco, na tabela permissao, e na hora de pesquisar eu veria se na lista de permissoes do cara tem alguma cuja variavel permissao é o que o metodo pede na anotação Role. No final o efeito seria o mesmo, mas ao invés de armazenar uma String na session, iria armazenar uma List… Poderia não guardar na session e pesquisar no banco toda requisição, mas ai acho que ia afetar demais a performance… o q q vcs acham?

O que seria a melhor solução?

Ao efetuar o login, tu carrega as permissoes do cara do banco de dados e joga num properties dentro da sessão dele.
tipo:

if(req.getParemeter("user").equals(usuario) && req.getParemeter("pass").equals("senha")){ java.util.Properties perm = new java.util.Properties(); perm.setProperty("add_usuario","true"); perm.setProperty("del_usuario","false"); //..... HttpSession ses = req.getSession(); ses.setAttribute("permissoes",perm); }

No caso tu faria tua verificação se o login do cara táva ok, se sim, tu faz uma consulta no banco e vai colocando no properties.
Depois nos outros servlet, tu obtem o properties da sessão e checa a permissão que tu quizer, tipo:

[code]//… um cod qualquer
HttpSession ses = req.getSession();
Properties perm = (Properties)ses.getAttribute(“permissoes”);
if(perm.getProperty(“add_user”) != null && perm.getProperty(“add_user”).equals(“true”){
// Codigo ok

}else {
// Codigo falhou.

}[/code]

Mais ou menos por ai. XD

Isso no caso do sistema ser web, se for desktop, tu pode armazenar o Properties em um Objeto que tu tenha acesso de qualquer lugar, ou pode colocar ele direto na tua classe usuario, algo tipo getPermissoes(), ao fazer o login tu chama setPermissoes jogando o properties preenchido no objeto usuario, quando precisar tu chama getPermissoes ou simplesmente cria uma função check(String permissao) dentro da classe usuario pra verificar se o usuario tem aquela dada permissão.

Entendi… mas vc acha essa opção muito vantajosa em relação à String?

Como falei no meu primeiro post, também tenho duvidas quanto a essa questão de permissoes.
A vantagem em cima da String é que tu não tem que trabalhar com indexOf ou algo parecido.
Tu poderia cria algo tipo no tu banco de dados:

create table permissoes( recurso char(50), permissao boolean default false, usuario integer not null )

sendo o campo usuario uma chave estrangeira apontando para uma tabela de usuarios.
Assim, quando o usuario fizesse login, tu pegaria todas as permissoes dele no banco e preencheria o objeto properties.
Tem tambem a questão de tu ficar com uma string gigantesca.
Não sei se realmente faz alguma diferença tu usar getProperty ou indexOf.
Se mais alguem entrasse na discução seria bom :smiley: .
Vê ai e me diz o que tu acha.
valeu.

É cara, acho que ninguém ta afim de discutir esse assunto e nos ajudar rs…

Um sistema com 1 usuario é igual a um sistema com multiplos usuários do ponto de vista das permissões.

O usuário ou tem permissões, ou não tem.
Este modelo implica em atribuir permissões a todos os usuários.

Um conceito interessante é atribuir ao usuário papeis no sistema (roles). Estes papeis são identificáveis através dos casos de uso.
É dificil para o usuário leigo ver a diferença mas com o tempo ele entende.

O sistema não é usado por pessoas, ele é usado por Usuários que desempenham certos papeis. E são os papeis que tem permissões associadas.

Em paralelo é possível agrupar os usuários por grupos e estabelecer papeis para o grupo. Isso facilita a administração do sistema, mas tb mascara as permissões e papeis de um usuário singular.

Outro tipo de permissão é especial ao usuário. Por exemplo, permissões delimitadas no tempo ( o usuário X não pode usar o sistema quando está de férias )

Então se o sistema precisa saber se usuários tem uma permissão especifica o usuário tem que lhe dizer isso
caso contrário, um controle apenas por papeis é suficiente.

O acesso especifico do usuário é controlado por usuário no login e o acesso às funções é controlado pelo papel.

O codigo padrão é

[code]if (user.hasRole(“rolename”)){

// faz algo protegido
}[/code]

para controle de funcionalidade, mas ele pode ir mais além se necessário, por exemplo

[code]if (user.hasPermission(new ThisFuncionalityPermission())){

// faz algo protegido
}[/code]

neste caso o objeto usuário procuraria nos roles se eles tem essa permissão e/ou procuraria na sua coleção de permissões particulares. A primeira versão é quase sempre suficiente, mas depende muito do tipo de sistema.

em HTML é legal ter um tag especial que vc posssa usar para retringir os usuários

[code]

[/code]

Este tipo de tag é usado para esconder visualizações da página.
Para controle de dados , menus etc… é melhor criar restrições no proprio codigo que gera esses artefactos.

Por exemplo, para criar o menu, um MenuBuilder deve ser criado e o usuário é passado como parametro.
O Builder então criará um menu ( padrão composite) que será correto para aquele usuário. internamente o builder
irá verificar as permissões pretinentes. O menu será colocado no escopo da página e simplesmente renderizado.
O codigo de renderização na página não precisa controlar o usuário porque o menu já foi garantidamente gerado especialmente para aquele usuário.

Ok Sergio, entendi sua logica. No caso ela se parece com o que falei antes.
Adicionar um Properties com as permissoes na classe usuario e implementar a funcao getPermissao.
De forma que ao executar uma ação protegia fariamos:

if ( user.getPermissao("permissao").equals("true") ) { ....... }

ou seguindo sua logica:

if( user.hasPermissao("permissao") ) { 
   .....
}

seria isso ?

[quote=lokidarkeden]Ok Sergio, entendi sua logica. No caso ela se parece com o que falei antes.
Adicionar um Properties com as permissoes na classe usuario e implementar a funcao getPermissao.
De forma que ao executar uma ação protegia fariamos:

if ( user.getPermissao("permissao").equals("true") ) { ....... }

ou seguindo sua logica:

if( user.hasPermissao("permissao") ) { 
   .....
}

seria isso ?[/quote]

Embora no fim dê no mesmo o seu codigo parte da idiea que permissão é mapeada para um string, quando na relalidade ela é um objeto por si mesmo. É a ausencia da permissão que impede o uso e não se for false . Ou seja, user.hasPermission() seria equivalente a

if ( user.getPermissao("permissao") !=null ) {
   .......
}

e getPermissao retornaria um objeto Permissao.

mas isso dá acesso a ler as permissões do usuário e até alterá-las. Por isso prefere-se hasPermissao
que pode fazer aquele if internamente sem expor a permissão ( que seria uma violação da segurança que vc está tentando criar)

Ok, entendi. Muito obrigado pela ajuda.

Algumas coisas se encaixam no modelo que estava utilizando, de ter uma String cheia de substrings indicando os roles do usuário certo?

Mas utilizar uma String para guardar todos os roles, ja que um usuário pode ter vários, é válido?