谈谈用户权限系统

登录这事之于一个需要识别用户身份的产品,就仿佛cs101之于computer science。感谢各种语言里各种优秀的登录模块(比如nodejs的passport),绝大多数产品,把它们拿来配置一下,闭着眼睛,花点功夫,就完成了一个从用户注册到登录一条龙的服务。很好很强大,不需要较真,也没人较真。

可登录还真是一件即便你半天就搞定还是需要好好较一下真的问题。本文回归本源,谈谈登录中那些极其重要又被人忽视的思想。

首先需要回答的一个问题是:要求用户登录的目的何在?

这个问题的答案是不言而喻的。服务器上的资源并非人人可以访问和操作,我们需要识别用户身份,从而了解他可以访问哪些资源,完成哪些操作。这里面隐含着几个重要的概念:

  • 资源(resource)
  • 操作(operation)
  • 身份,或者角色(role)

先看「资源」。如果你设计一个聊天系统,那么,为聊天而建的群组(channel),在群组中大家畅所欲言发表的信息(message)就是资源的概念。这个很好理解。

「操作」是附着在「资源」上的用户行为。在某个资源上,最基本的操作是:读(read),写(write),执行(execute)。那么,读/写/执行究竟怎么理解呢?聊天系统列出(list)当前所有可见的群组,或者显示(show)某个群组下的某条聊天记录,这便是读操作;某个用户创建(create)一个群组,修改(update)群组信息,发表(create)聊天记录,撤销(delete)一条聊天记录,这些都是写操作的范畴。至于在聊天记录里面全文搜索(search),存档(archive)旧的聊天记录,可以被视作执行。

操作

示例

列出所有群组/显示某条聊天记录,或者说 list/show

创建群组/修改群组信息/发表聊天记录/撤销聊天记录,或者说 create/update/delete

执行

全文检索/存档,或者说 search/archive

读/写/执行是最基本的操作,而list/show/create/update/delete/search/archive是具体的操作。

「角色」是一个用户属性,定义用户对资源的访问权限。上述的聊天系统可能的角色有:所有用户(all users),匿名用户(anonymous users),已登录用户(authenticated users),群主(更广义一些说,resource owners)以及管理员(administrators)。这五个角色是一个系统最基本的角色,在此基础上可以衍生出来一些特定的角色,比如群成员。

对于一个「角色」来说,其访问权限可以通过访问列表(ACL,access list)来定义。一般而言:

  • 所有用户不能进行任何操作
  • 匿名用户可以进行读操作
  • 已登录用户可以进行创建资源(特定的写操作)
  • 资源拥有者可以对自己创建的资源进行任何写操作(修改/删除)
  • 管理员可以对任何资源进行写操作

web应用的访问列表的功能可以类比网络中的防火墙的功能:

对于我们举的聊天系统的例子,具体的访问列表可能是这个样子:

  • 所有用户不能进行任何操作
  • 匿名用户只能执行登录/注册操作
  • 已登录用户可以创建群组(写)
  • 已登录用户可以读取群组列表(读)
  • 已登录用户可以加入群组(执行)
  • 群成员可以发信息(写)
  • 群成员可以删除自己最后发出的信息(写)
  • 群主可以修改群组信息(写)
  • 群主可以批准加入请求(执行)
  • 群主可以把不良分子驱逐出群(执行)
  • …(管理员就不列了)

把这些访问列表以yaml的形式定义,大概是这个样子:

当系统里每个角色都有了定义清晰的访问列表后,一个用户的登录行为实际上就是动态迁移角色的行为。比如说,登录前小明的角色是 [所有用户, 匿名用户],登陆后他的角色转化为 [所有用户, 已登录用户],当他创建群组A后,并进入群组A后,他的角色转化为 [所有用户, 已登录用户, A群成员, A群群主],当他加入群组B,开始聊天时,他的角色又转化为 [所有用户, 已登录用户, B群成员]。无论小明访问系统的哪个部分,我们都能找到他对应的角色,进而算出他拥有的权限的集合(所有角色的访问列表的并集)。

有同学可能会认为「所有用户」这个角色,以及「所有用户不能进行任何操作」这个访问列表有些多余,其实,这正是系统设计严密性的一种体现。就如一个防火墙,其默认的策略是「从任意源到任何目的地的网络数据都丢弃」,或者一段switch case,最后总需要有一个default是同一个道理。一个用户在极端的情况下可能没有附加任何角色,或者请求的操作并未找到对应的访问列表,那么能唯一匹配的访问列表就是「所有用户不能进行任何操作」(all, *, *, DENY),所以不允许他做任何事情,在逻辑上是严密的。

定义好了资源,对资源允许的操作,用户可以附加的角色,以及角色拥有的访问列表这些最基本的内容之后,整个用户权限系统就清晰多了。你再也不必用散落在各处的代码苦心孤诣地从上下文里扒拉出来这个用户究竟允不允许做当前的操作,而是通过在请求的入口处设立一道闸门(middleware),挡掉不合法的请求,只允许合法的请求通过这道闸门,闸门的设计很简单:

guard(resource, operation, role_list)

其中,resource和operation必然在请求中包含,比如一个http请求:https://api.chat.xyz/channels/wtf/actions/send/, wtf(组名)就是resource,send就是operation。而role_list可以在user session里找到。

这大大简化了权限处理,而guard本身,实际上就是一个acl lookup engine。你可以找现有的解决方案,也可以把所有定义好的访问列表塞到一个hash table里,放在redis里进行快速查询,当然,如果你会一门趁手的函数式编程语言,比如elixir,可以直接做pattern matching:

def do_guard("channel", "$owner", "$execute") do
    "ALLOW"
end

...

def do_guard(_, _, "$all") do
    "DENY"
end

对于那些允许管理员在后台修改访问列表的系统,我们还可以使用使用elixir的macro功能,在每次后台修改完成后,触发重新生成acl lookup engine,并利用erlang VM的特性,hot code reload到系统中。

原文发布于微信公众号 - 程序人生(programmer_life)

原文发表时间:2015-08-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏JasonhavenDai

小爬虫之爬取淘宝MM1.技术路线2.目标3.分析4.运行结果5.源码

1.技术路线 python3 urllib re mysql sqlyog 2.目标 爬取淘女郎的MM信息 3.分析 网站:https://mm.taobao....

34970
来自专栏北京马哥教育

一篇了解爬虫技术方方面面

原理 传统爬虫从一个或若干初始网页的URL开始,获得初始网页上的URL,在抓取网页的过程中,不断从当前页面上抽取新的URL放入队列,直到满足系统的一定停止条件...

46490
来自专栏Python小屋

Python截屏扩展库pyscreenshot安装与使用

PIL是非常成熟的Python图像处理扩展库,但只支持Python 2.x,另一个同样功能的扩展库pillow完美支持Python 3.x。然而,这两个库的部分...

27530
来自专栏魏艾斯博客www.vpsss.net

宝塔面板网站备份迁移到新服务器的过程

最近群里有朋友问到宝塔面板的网站如何备份和搬家到新服务器,对于老手来说很简单了,但是对新手来说还需要有一步步学习的过程。为了方便众多新手学习、操作,魏艾斯博客总...

3.5K20
来自专栏一“技”之长

Xcode创建可复用的代码块 原

        在各种程序开发中,编写代码的效率是非常重要的一个问题,各种优秀的编译器也都有相应的插件用于提高程序员的编码速度。在xcode中,可以通过定义代码...

15420
来自专栏java 成神之路

iostat 命令详解

39290
来自专栏Laoqi's Linux运维专列

“考虑不全面”导致的大问题!!!

今天做了个小实验,由于自己的考虑不全面,导致了大问题的产生! 因为此问题我在全网几乎都未找到满意的答案,所以现在打算分享出来! 问题原因: 1 2 ...

42380
来自专栏Script Boy (CN-SIMO)

搜狗输入法linux安装 以及 12个依赖包下载链接分享

搜狗输入法linux安装版,先安装各种依赖包,大概12个依赖,可能中途还需要其他依赖,可以效仿解决依赖问题。 如图这12个文件要是手动点击下载,那也太笨点了,我...

37500
来自专栏好好学习吧

LoadRunner菜鸟入门学习笔记

  11.0 最高ie9( win7 32位+LR11+IE10可用,但win7 64位+LR11+IE10不可用,降至IE9可用),支持firefox3.6、...

1.5K20
来自专栏WeTest质量开放平台团队的专栏

面向Unity程序员的Android快速上手教程

随着Unity、cocos2dx等优秀跨平台游戏引擎的出现,开发者可以把自己从繁重的Android、iOS原生台开发中解放出来,把精力放在游戏的创作。原来做一款...

15830

扫码关注云+社区

领取腾讯云代金券