As verificações de permissão do usuário devem ocorrer no modelo ou no controlador? E quem deve lidar com as verificações de permissão, o objeto Usuário ou algum auxiliar do UserManagement?
Onde isso deveria acontecer?
Verificando no controlador:
class MyController {
void performSomeAction() {
if (user.hasRightPermissions()) {
model.someAction();
}
}
...
A realização de verificações no Controlador ajuda a simplificar as ações dos Modelos, para que possamos manter toda a lógica para os Controladores.
Verificando o modelo:
class MyModel {
void someAction() {
if (user.hasRightPermissions()) {
...
}
}
...
Ao colocar as verificações no Modelo, complicamos o Modelo, mas também garantimos que não permitimos acidentalmente que os usuários façam coisas que não deveriam no Controlador.
E por quem?
Depois de nos estabelecermos no local, quem deve fazer as verificações? O usuário?
Class User {
bool hasPermissions(int permissionMask) {
...
}
...
Mas, na verdade, não é responsabilidade do usuário saber o que ele pode acessar, talvez uma aula auxiliar?
Class UserManagement {
bool hasPermissions(User user, int permissionMask) {
...
}
...
Eu sei que é comum fazer apenas uma pergunta, bem, uma pergunta, mas acho que elas podem ser respondidas muito bem juntas.
fonte
A segurança é uma preocupação transversal, portanto, precisa ser implementada em várias camadas. A seguir, é apresentado um exemplo para o MVC, mas o conceito se aplica a outras arquiteturas e / ou padrões, basta identificar os pontos de aplicação.
Onde isso deveria acontecer?
As visualizações podem conter elementos da interface do usuário (widgets, botões, menus etc.) que precisam ser exibidos ou não para alguns usuários, com base em suas permissões. Isso pode ser uma responsabilidade do mecanismo de exibição , pois você não deseja que cada exibição lide com isso por conta própria. Dependendo do tipo de elementos que você está autorizando, mova essa responsabilidade para outro local. Por exemplo, pense em um menu no qual alguns itens precisam ser exibidos e outros não. Os itens podem ser implementados como uma lista em algum lugar e filtrar essa lista com base nas permissões e encaminhá-la para a exibição.
Os controladores respondem às solicitações; portanto, se um usuário não tiver permissão para executar uma ação, ele deverá ser verificado antes que a ação seja invocada, movendo a responsabilidade para o invocador da ação, em vez de mantê-la no controlador. Isso tem a vantagem de manter seu controlador limpo e, se algo mudar nas permissões, você não precisará examinar seus controladores para aplicar essas alterações.
Os recursos são exibidos com base nas permissões. Isso normalmente é feito no nível do banco de dados , pois você não deseja extrair tudo do banco de dados e aplicar permissões.
Como você pode ver, dependendo do que você deseja autorizar, existem diferentes locais onde isso deve ser feito. O objetivo é ser o mais discreto possível, para que, quando sua política de segurança for alterada, você possa aplicá-la facilmente, de preferência sem alterar o código do aplicativo. Isso pode não ser válido para aplicativos pequenos, onde o conjunto de permissões é bastante pequeno e não muda com muita frequência. Em aplicativos corporativos, porém, a história é bem diferente.
Quem deve fazer isso?
Claramente não é o modelo. Cada camada deve ter um ponto de aplicação que lida com a autorização. O texto em itálico acima destaca o possível ponto de execução para cada nível.
Dê uma olhada no XACML . Você não precisa implementá-lo como está, mas ele fornecerá algumas orientações que você poderá seguir.
fonte
Eu uso o seguinte esquema. Vale dizer que a maioria das verificações de permissões de usuário pode ser dividida em dois casos gerais:
O acesso à ação do controlador sem verificação de atributos geralmente é implementado nas estruturas MVC. Isso é simples: você define regras, seus usuários têm papel. Você simplesmente verifica se o usuário tem permissão para procurar ações em suas regras.
O acesso do usuário a determinado modelo deve ser definido no modelo. (O ator é a classe de usuário base. Suponha que possa ser cliente, vendedor ou convidado.)
Colocar essa lógica no modelo traz algum lucro. O método de verificação de acesso pode ser herdado, você não precisa criar nenhuma classe extra, pode usar vantagens gerais de OOP.
Em seguida, para simplificar a verificação de acesso, adotamos algumas premissas que quase sempre são implementadas já por simplicidade e bom estilo:
Com essas suposições, as ações que usam o ID do modelo podem ser associadas a uma instância específica do modelo. De fato, a maioria das ações pode ser facilmente transformada e movida para se ajustar às suposições mencionadas acima.
Então, alguma classe de controlador abstrata de base deve ser definida e herdada.
Você pode chamar o método SomeController :: checkModelAccess ($ id) quando criar seus menus e decidir se deseja mostrar algum link.
fonte
No modelo e na vista
Na exibição - porque a interface do usuário não deve mostrar os elementos da interface do usuário restritos ao usuário atual
(por exemplo, o botão "Excluir" deve ser exibido para pessoas com permissões apropriadas)
No modelo - porque seu aplicativo provavelmente tem algum tipo de API, certo? A API também deve verificar as permissões e provavelmente reutiliza o modelo.
(por exemplo, você tem o botão "Excluir" na interface do usuário e o método da API "http: / server / API / DeleteEntry / 123" ao mesmo tempo
fonte
MVC é um padrão de apresentação. Como tal, a visão e o controlador devem ter apenas responsabilidades em relação à apresentação. Algumas permissões se aplicam à apresentação, como um modo especialista, recursos experimentais da interface do usuário ou designs diferentes. Esses podem ser manipulados pelo controlador MVC.
Muitos outros tipos de permissões são relevantes em várias camadas do aplicativo. Por exemplo, se você deseja ter usuários que podem apenas visualizar dados e não alterar coisas:
Há alguma duplicação nessa abordagem. Porém, como a apresentação é geralmente volátil, pode-se defender a verificação de permissão na parte geralmente mais estável do aplicativo, mesmo que isso signifique algumas verificações redundantes, caso a camada de apresentação funcione como pretendido.
fonte