Normalmente, eu coloco decisões de autorização nos controladores do servidor. Esses foram os pontos de extremidade RESTful recentemente, mas acho que o mesmo vale para as arquiteturas do tipo MVC. Por uma questão de argumento, assuma que é uma autorização baseada em função. Um método protegido será anotado ou fará verificações e retornará 403s, se necessário.
Agora, considerando que a autorização é de fato uma regra comercial - "apenas administradores podem listar X", por exemplo, acho que eles devem ser empurrados para uma camada. Quando um controlador solicita que a camada de negócios execute a operação, o serviço ou a camada de negócios informa ao controlador que não está autorizado.
Essa é uma abordagem razoável? Existem desvantagens nisso?
Detesto ter um AuthorisationService que essencialmente contém um monte de regras codificadas de procedimentos estáticos para fazer isso, mas talvez faça sentido manter toda a lógica de acesso em um único local. É uma preocupação transversal que deve ser mantida em separado?
Então, eu estou perguntando se alguém fez isso e como eles conseguiram isso de uma maneira limpa ou se existem bons recursos que eu possa ler. Estou usando o Java fwiw, mas esta é uma questão independente da linguagem.
Eu verifiquei as perguntas relacionadas aqui e elas são muito finas no chão e respostas. Por exemplo: Validação e Autorização em Modelos de Domínio e Transmitindo isso através de uma Camada de Serviço para MVC
Estou lendo os documentos de segurança da primavera que apresentam bons argumentos por se tratar de uma preocupação transversal, mas estou preocupado que seja apenas o "caminho da primavera" e que gostaria de ter perspectivas mais amplas. Também vincula seu aplicativo a uma estrutura específica.
fonte
Respostas:
É uma boa prática expor apenas as opções para as quais um usuário está autorizado.
Isso força a autorização a ser uma preocupação transversal. A "Visualização" precisa saber o que um usuário pode fazer antes de criar opções e menus para exibição.
O back-end não deve confiar no front-end para tomar decisões de segurança, portanto, deve verificar a própria autorização.
Pode haver regras comerciais que efetuem a autorização dependendo dos dados, por exemplo, "Somente usuários com saldo acima de US $ 5.000 podem invocar uma transferência de moeda estrangeira" ou "Somente um usuário localizado na matriz pode visualizar essas contas". Portanto, é necessária alguma lógica de autorização dentro da lógica de negócios.
Também há autorizações técnicas a serem consideradas - quem tem permissão para visualizar os logs, quem pode fazer backup / restaurar o banco de dados etc.
Portanto, no final, todos os componentes do seu site podem ter alguns requisitos específicos de segurança e / ou autorização, na prática é quase impossível agrupar isso em uma "camada de autorização" separada.
fonte
Eu acho que é uma abordagem absolutamente razoável obter autorização na sua camada de Serviço. Você precisa proteger seu serviço contra atividades não autorizadas (especialmente modificações de dados). Sua camada de serviço pode residir em uma biblioteca e ser usada por diferentes camadas de apresentação (você pode ter diferentes aplicativos de interface do usuário que usam a mesma camada de serviço). E você não pode confiar no fato de que camadas específicas da apresentação executam a validação necessária. Isso é especialmente importante se você decidir posteriormente mover sua camada de Serviço para o processo separado (por exemplo, seguindo a abordagem SOA).
Agora, sobre como conseguir isso de uma "maneira limpa". Não gosto da idéia de jogar lixo na lógica de negócios com verificações de autorização; portanto, alguma implementação específica da abordagem de programação orientada a aspectos pode ajudar: pode ser decorar métodos de serviço com atributos especiais ou usar proxies dinâmicos com interceptações.
E, mais importante, preciso admitir que, em projetos muito simples, você pode viver sem validações separadas, apenas para simplificar sua vida. Mas é importante não perder o momento em que "projeto simples" começou a se tornar "projeto complexo".
fonte
Eu gosto de baixar as verificações de autorização o mais baixo possível! (Mas não mais!)
Você ainda pode escrever testes de autorização automatizados nas camadas "acima" disso. E algumas regras podem ser aplicáveis apenas ou fazer sentido em camadas superiores, como a camada de serviço (CanView / CanSerialize?). Porém, geralmente penso que a estratégia de autorização mais segura também é a estratégia "DRY-est": mantenha a autorização o mais baixa possível, no código mais "comum" ou "compartilhado" possível (sem complicar demais as regras de autenticação).
Pense na alternativa. Se suas regras de autorização forem testadas e aplicadas apenas na camada de serviço, deixando seus objetos de domínio ruim se dobrarem às vontades de objetos de serviço mal-humorados, muitas vezes você precisará impor cada regra individual mais de uma vez, em vários objetos e vários lugares em cada objeto e em código mais complicado.
Além disso, quando sua equipe de análise contrata uma empresa de consultoria para escrever serviços de relatório usando seus objetos de domínio, você não precisa confiar nesses desenvolvedores! (Ou seja o que for. Você cria serviços ou chamadas adicionais sobre os mesmos objetos por qualquer motivo.) Você não vai querer abrir o grande livro de regras de negócios e esperar aplicá-las adequadamente novamente ; você deseja que seu domínio já os conheça e faça cumprir.
fonte
Widget
, a mesma regra se aplicará a todos os lugares. (Então não arriscar deixar ninguém ignorá-lo!) Se a regra não se aplica em todos os lugares, não é realmente uma regra sobreWidgets
e únicaWidgets
. . Empurre as regras para baixo o máximo possível (as regras individuais); mas, não tão longe como "regras" pode ir ... Eu sinto que não estou afirmando a distinção bem. Mas, é suposto haver distinção lá.