Modeling for user permissions

6

I think this question is more about modeling analysis actually do not know if it fits into the standard questions discussed by meta.pt.stackoverflow.com . I need to make my system in a way that almost everything will have user permissions, I made the following modeling of entities

ButmaybeIhavetoput"ACCESS and CRUD" permissions to the product manufacturer or permissions for the user that does not have to do with the category or manufacturer, for example: permissions for user to register other users and give permissions to them , the problem is that in my current style of modeling I would have to create another table of permissions for the manufacturer and another table of permissions for registering other users, I would like to know if there is any modeling pattern (Designer Patterns) for this type of situation?

  

Diagram: Link

    
asked by anonymous 28.03.2014 / 18:23

1 answer

6

There are two options for you here: without referential integrity and with . A without is certainly simpler if you do not mind the lack of foreign keys, but if you find this indispensable there is an alternative with them - however you will not escape creating an additional table for each entity in your model. / p> To get started, create the basic templates: Usuario , Grupo , Permissao , and the many-to-many GrupoUsuario , PermissaoUsuario , and PermissaoGrupo associations. This separation will make your life much easier. Explanation: A user belongs to zero or more groups and has zero or more permissions. In addition, the user inherits group permissions (i.e. does not need to explicitly assign a permission if one of the groups where it is already has this permission).

You can omit Grupo if you want to simplify your model, at the expense of a greater number of objects of type PermissaoUsuario (since each new user must explicitly receive all permissions). Alternatively, you can omit PermissaoUsuario if you are not interested in giving individual permissions to a user, only indirectly through a group. It's up to you.

Solution without referential integrity

The Permissao template should be kept as simple as possible: the nome of the permission, the tabela it refers to, and the linha in the table (possibly NULL ), if applicable. Example:

Permissao
nome             tabela         linha
-------------------------------------
create           Produtos       NULL         <-  Usuário pode criar Produtos
read             Produtos       42           <-  Usuário pode ler o produto 42
read             Fornecedores   NULL         <-  Usuário pode ler Fornecedores

Verifying that a user is allowed to access a record is simple:

select 1
    from Usuario u
         join PermissaoUsuario pu on pu.id_usuario = u.id
         join Permissao        p  on pu.id_permissao = p.id
    where
         u.id = 10 and
         p.nome = 'read' and
         p.tabela = 'Produtos' and
         (p.linha = 42 or p.linha is null)
union
select 1
    from Usuario u
         join GrupoUsuario   gu on gu.id_usuario = u.id
         join PermissaoGrupo pg on pg.id_grupo = gu.id_grupo
         join Permissao      p  on pu.id_permissao = p.id
    where
         u.id = 10 and
         p.nome = 'read' and
         p.tabela = 'Produtos' and
         (p.linha = 42 or p.linha is null);

(Remember: if you omitted Grupo or PermissaoUsuario the bottom or top of union , respectively, is not required; and this is null test is only in case a user has permission to access all table rows, if your model does not have it then you can omit that part)

Solution with referential integrity

In this case your Permissao template will only contain nome (ie it will not have tabela nor linha ), but a series of other templates will be created to represent the permission to access a specific line of a specific model. For example:

create table PermissaoProduto(
    id_permissao integer not null,
    id_produto   integer not null,
    primary key (id_permissao),
    foreign key (id_permissao) references Permissao(id),
    foreign key (id_produto)   references Produtos(id)
);

The rest stays the same. Thus, every line of PermissaoProduto will be inheriting from a line of Permissao - since both have the same primary key. The referential integrity of Usuario is for Permissao , referential integrity for Produtos is for PermissaoProduto . The permission check is also simple, it only has a join more:

select 1
    from Usuario u
         join PermissaoUsuario pu on pu.id_usuario = u.id
         join Permissao        p  on pu.id_permissao = p.id
         join PermissaoProduto pp on p.id = pp.id_permissao
    where
         u.id = 10 and
         p.nome = 'read' and
         pp.id_produto = 42
union
select 1
    from Usuario u
         join GrupoUsuario   gu on gu.id_usuario = u.id
         join PermissaoGrupo pg on pg.id_grupo = gu.id_grupo
         join Permissao      p  on pu.id_permissao = p.id
         join PermissaoProduto pp on p.id = pp.id_permissao
    where
         u.id = 10 and
         p.nome = 'read' and
         pp.id_produto = 42;

Although it seems complicated at first glance, keeping a table of permissions different for each model, the integration between each type of permission and the user is the same - because it occurs through the Permissao table. Personally, I would use the solution without referential integrity, but it is up to each one.

    
28.03.2014 / 19:45