显式授权中的数据重复

时间:2015-05-12 20:44:40

标签: permissions authorization relational-database rdbms

我们当前在我们网站上的授权策略与我们的RDB架构紧密耦合 - 这在某些方面是一件好事,因为这意味着用户可用的权限与他应有的权限完全匹配,假设正确解释数据。因此,当我们查询授权时,我们会询问外键/ m2m关系。

我看到了两个主要问题:首先,解释关系数据要比从单独的表中读取显式权限要困难得多。我看到的更大问题是这不会扩展。随着应用程序的增长,我们的权限检查已从三个表中的单个查询变为跨越十个或更多表的多个查询。

我在许多解决此问题的地方看到的策略是明确授权(例如角色或基于声明)。因为这种事情很简单,只需坚持一个表,它就更简单,更快速,更具可扩展性。困扰我的是这样的:你如何避免重复数据?

例如,我有一个拥有设计的用户。目前用外键完成了。在切换到显式授权时,我会将用户的ID添加到包含设计ID和类型的表中。我也应该删除外键吗?权限相关关系是否总是由权限表调解,还是应该在关系表示和权限表之间复制数据?

似乎移动到显式授权的缺点可能包括性能,特别是如果需要服务调用或某些东西来完全发现权限。

1 个答案:

答案 0 :(得分:1)

I think you're on the right track with roles.

When logging in, you should request your roles as scopes. It's not a terrible idea to namespace them by API and maybe group ids, if they apply.

for file in *;
do
    echo $file
done

The login service could then validate that role by asking the service associated with the namespace.

scopes: ['forum:admin:somegroupid']

Which then returns whether that user can have that scope and the description of thats scope. Then the login service may include that scope in the generated jwt for that request.

Non subselected scopes should be validated at the route level (say if it were a role that wasn't specific to any group or item).

Otherwise, you'll have to do a query to see if that service says that the userid or one of the included scopes is allowed to do the thing. Redis SETs might be nice for this if you didn't want it to be a foreign table.

I think for object-level permissions, joining to a an access table makes sense, but use it as sparingly as possible. For example, in a forum-setting, object-level permissions should be on the forum, not at the threads or post level (except for owners, that are just included in row with the data). Then you can join from post->thread->forum_access to see whether they can write a new object.

TLDR; Use roles when possible and include as scopes that are validated at a route level. Use group level roles as scopes if necessary. Minimally use object-level permissions only when necessary, only on the objects absolutely necessary.

Edit: This is just one of many possible ways to solve your problem.