Estou olhando para o design da minha interface e estou lutando para decidir qual é a maneira mais "correta" de implementar o controle de acesso baseado em funções, dado a user
e a subject
que user
eles gostariam de acessar.
Tanto quanto posso ver, tenho três opções principais (com uma quarta sendo uma bastardização dos três primeiros e uma quinta sendo uma emenda do quarto):
- Consulte a
subject
lista de permissões queuser
possui -subject.allowAccess(user.getPermissionSet)
- Consulte o
user
com uma lista de permissões que osubject
requer -user.hasPermissionTo(subject.getRequiredPermissions())
- Consulte um terceiro para localizar as interseções de permissões -
accessController.doPermissionSetsIntersect(subject.permissionSet, user.getPermissionSet())
- Consulte o
subject
/user
enquanto delega a "decisão" para uma classe de terceiros - Tente
user
acessarsubject
e gerar um erro se o acesso não for permitido
Estou inclinado para a opção quatro - subject
Contenha um accessController
campo, onde chamadas para subject.userMayAccess(User user)
delegar a operação a la:
class Subject {
public function display(user) {
if(!accessController.doPermissionSetsIntersect(this.permissionSet, user.getPermissionSet())) {
display403(); //Or other.. eg, throw an error..
}
}
}
.. mas isso levanta outras questões:
- deve
accessController
ser um campo vs uma classe estática ..? - Deveria
subject
saber quais permissões são necessárias para poder visualizá-lo? - onde o princípio do menor conhecimento entra em jogo aqui, com relação ao chamado
subject.display()
? Os chamadores devemsubject.display()
saber que o controle de acesso está em vigor? (ondesubject.display()
é um "método de modelo" final) - ter
subject.display()
gerenciar o controle de acesso, lançar uma exceção, onde o usuário não tem a permissão necessária?
O que seria considerado "melhor prática" nessa situação? Onde deveria ocorrer a responsabilidade pela realização das verificações?
Como esse é um exercício acadêmico que progride para a implementação, as referências aos padrões de design seriam apreciadas.
Penso que a sua opção 3 é o mais próximo, mas em vez de interrogar o
user
esubject
sobre os seus conjuntos de permissões que você deve passar ouser
esubject
ao controlador de acesso.O controlador de acesso deve ser responsável por obter os conjuntos de permissões e verificar se o acesso é suficiente. Dessa forma, você isola a lógica de armazenamento e a lógica de verificação em seu controlador de acesso, separadas do usuário e do assunto.
O outro elemento possivelmente ausente do seu exemplo é qual operação está sendo executada. Alguns usuários podem ter o direito de ler alguns dados, mas não atualizar, excluir, executar, etc Então, você pode ter um
checkAccess
método no controlador de acesso com três parâmetros:user
,subject
,operation
. Você também pode fornecer algumas informações adicionaischeckAccess
para retornar informações sobre por que o acesso não foi concedido.Por exemplo, delegar tudo isso ao controlador de acesso posteriormente permite substituir a maneira como suas permissões são representadas. Você pode começar com o controle de acesso baseado em função e passar para baseado em declarações posteriormente. Você pode armazenar permissões em uma estrutura simples para começar e depois adicionar grupos / funções hierárquicos e operações permitidas em diferentes tipos de assuntos. Não colocar seus conjuntos de permissões na interface ajuda a habilitar isso.
Se você usa AOP ou algum código padrão para conectar isso é, na minha opinião, menos importante.
fonte