Estou tentando adicionar a capacidade de um usuário ser autorizado com uma determinada função em um contrato/site/experimento.
Mais especificamente, quero que um usuário tenha a função A em um contrato, mas ao mesmo tempo a função B em um site específico desse mesmo contrato e possivelmente uma função C em um experimento desse site.
Minha primeira ideia foi uma tabela de junção entre User
e Role
com uma terceira coluna armazenando o id de um contrato, site ou experimento.
Esta solução tem muitos problemas na minha opinião:
- Preciso de uma linha para o contrato, cada site autorizado e cada experimento autorizado. Pode crescer muito muito rápido.
- Nenhuma integridade. Um contrato inexistente pode ser referenciado
- Se eu quiser saber todos os sites e experimentos de um contrato onde um usuário está autorizado, primeiro tenho que consultar todos os sites desse contrato, depois todos os experimentos desses sites e então encontrar todas as linhas que fazem referência a esses IDs. Parece um pouco hackeado.
Sinto que essa solução pode funcionar, mas eu estava pensando se havia outra maneira? Talvez algum padrão que eu não conheça?
PS: Estou usando MySQL v8
Este pode ser um bom primeiro macarrão molhado para jogar na parede. A tabela person_role aqui é um pouco estranha. O contract_id, site_id e experiment_id são anuláveis e deve haver uma restrição de verificação garantindo que exatamente um deles seja não nulo. Com isso, você pode usar uma abordagem em cascata. Se um sujeito estiver trabalhando em um experimento, mas não tiver nenhum privilégio explicitamente definido para ele naquele experimento, então os privilégios que ele tem no nível do site seriam usados. E assim por diante com o contrato.
Quaisquer privilégios concedidos/negados em um nível inferior prevalecerão sobre as configurações em um nível superior.
Graças à resposta de @Doug Hills, adaptei meu esquema inicial e acabei com este esquema
Substituí as colunas polimórficas por 3 chaves estrangeiras (
siteId
eexperimentId
são anuláveis) e removi o deny/access de role_privilege e adicioneiautoGrantAccess
a person_role.autoGrantAccess
é um booleano, se verdadeiro um usuário é autorizado em todos os recursos filhos, se falso os recursos filhos têm que ser explicitamente autorizados. É um pouco estranho, mas é uma solução para recursos filhos sendo adicionados depois que um usuário é autorizado no recurso pai.Se um usuário for autorizado em todos os sites de um contrato, exceto um, isso significa adicionar n-1 linhas, mas no meu caso de uso isso não deve acontecer com muita frequência. E se acontecer, ainda posso adicionar um
deny
booleano aperson_role
.