Eu não teria escolhido pronunciar o comentário original da maneira como foi redigido, mas ele identifica um problema potencialmente legítimo.
Especificamente, as preocupações que justificam a separação são autenticação vs. autorização .
Autenticação refere-se ao processo de login e obtenção de uma identidade. É como os sistemas conhecem quem você é e são usados para coisas como personalização, propriedade de objetos, etc.
Autorização refere-se a o que você pode fazer , e isso (geralmente) não é determinado por quem você é . Em vez disso, ele é determinado por alguma política de segurança, como funções ou permissões, que não se importam com coisas como seu nome ou endereço de e-mail.
Estes dois podem mudar ortogonalmente entre si. Por exemplo, você pode alterar o modelo de autenticação adicionando fornecedores OpenID / OpenAuth. E você pode alterar a política de segurança adicionando uma nova função ou mudando de RBAC para ABAC.
Se tudo isso for feito em uma classe ou abstração, seu código de segurança, que é uma das ferramentas mais importantes para a redução de riscos, torna-se, ironicamente, de alto risco.
Trabalhei com sistemas em que a autenticação e a autorização estavam muito juntas. Em um sistema, havia dois bancos de dados de usuários paralelos, cada um para um tipo de "função". A pessoa ou equipe que projetou isso aparentemente nunca considerou que um único usuário físico pode estar em ambas as funções, ou que pode haver determinadas ações que eram comuns a várias funções, ou que poderia haver problemas com colisões de User ID. Este é um exemplo reconhecidamente extremo, mas foi incrivelmente doloroso de trabalhar.
Microsoft e Sun / Oracle (Java) referem-se ao agregado de informações de autenticação e autorização como Principal de Segurança . Não é perfeito, mas funciona razoavelmente bem. No .NET, por exemplo, você tem IPrincipal
, que encapsula o IIdentity
- o primeiro sendo um objeto política (autorização) enquanto o último é um > identidade (autenticação). Você poderia razoavelmente questionar a decisão de colocar um dentro do outro, mas o importante é que a maioria do código que você escreve será para apenas uma das abstrações , o que significa que é fácil de testar e refatorar.
Não há nada errado com um campo User.IsAdmin
... a menos que também haja um campo User.Name
. Isso indicaria que o conceito "Usuário" não está adequadamente definido e isso é, infelizmente, um erro muito comum entre os desenvolvedores que estão um pouco molhados atrás das orelhas quando se trata de segurança. Normalmente, a única coisa que deve ser compartilhada por identidade e política é a ID do usuário, que, não coincidentemente, é exatamente como ela é implementada no Windows e no * nix modelos de segurança.
É completamente aceitável criar objetos wrapper que encapsulem identidade e política. Por exemplo, isso facilitaria a criação de uma tela de painel em que você precisa exibir uma mensagem "hello" além de vários widgets ou links que o usuário atual tem permissão para acessar. Contanto que esse wrapper apenas contenha as informações de identidade e política, e não reivindique a propriedade dele. Em outras palavras, desde que não esteja sendo apresentado como uma raiz agregada .
Um modelo de segurança simplista sempre parece uma boa idéia quando você cria um novo aplicativo, por causa do YAGNI e tudo mais, mas quase sempre acaba voltando para te morder mais tarde, porque, surpresa surpresa, novos recursos são adicionados!
Portanto, se você souber o que é melhor para você, manterá as informações de autenticação e autorização separadas. Mesmo que a "autorização" agora seja tão simples quanto um sinalizador "IsAdmin", você ainda estará melhor se não fizer parte da mesma classe ou tabela que as informações de autenticação, para que, se e quando sua política de segurança precisar mudar, você não precisa fazer cirurgia reconstrutiva em seus sistemas de autenticação que já funciona bem.