前言对于管理自己群的销售人员,我们来将用户的销售数据进行分组。场景二:马里奥,今天市场部说要分开几个版块,公众号会管理所有的文章投稿和评论,推广会管理各平台的宣传策略计划和执行。是的,竞品的相关信息和数据也应该分开。我们要把它们分开。之前讨论的销售部的事情与此无关。场景三:嗯,xx店老板说,他管理的两家店要同时处理两家店的事务,需要兼顾两家店的销售和进货数据。别人说的需求场景说的有道理,你给他做就行了,对了,别影响其他店的管理!场景四:今天总部运营经理说,他们要从门店、部门、个人用户的角度来看所有的门店。让我们为他们做吧。天天导入excel要疯了。我们一开始讲权限,很容易想到在用户发起请求的时候在界面上做一层权限校验,或者限制读写数据库的权限,简单粗暴。因为限制是基于用户操作的,所以我们在一个接口的handler中定义:ifnotuserin['xxx','yyy','zzz']:return'hasnopermission!'或者在处理数据模型的model层定义:access_users=['xxx','yyy','zzz']限制用户的操作行为。然而,这种硬编码形式简直太可怕了。今天添加一个接口,我们将在处理程序代码中定义一段此权限。明天,另一个处理程序的权限发生变化,我们将再次更改该代码。你说写在装饰器里统一管理,ok,那在添加修改handler的时候,也需要找到对应的有权限的用户,在装饰器里定义。在产品不断迭代的场景下,这是不可接受的。所以我们有必要引入一个模型来规范权限控制。结构化管理通过以上场景,我们很容易得到一个user(单个用户)、group(用户组)、permissions(单一权限)多对多关系的权限结构模型(参考django)。实现了当用户请求接口APIa时,此时获取到的是用户,用户所属的组,以及用户所属组的权限。如果无法获得记录,则限制请求。利用这个模型,我们每次都以模块和函数的形式定义权限,同时定义请求方法。这将一个组与一个权限(即一个处理程序)的权限相关联。同时,将用户与用户组关联起来,这样在权限不断变化的情况下,可以配置一个对应关系,将用户权限限制在单个handler。使用python的同学都知道,由于python装饰器@的语法糖,我们喜欢用这种形式来处理这些与业务逻辑无关的代码,比如日志记录、检查缓存、检查用户session等。有时候写的像在方法装饰器里建楼,一不小心就忘记了。有时候开发者对项目不熟悉,写完新的接口,配置权限,却忘了加装饰器,导致这部分没有被限制。@route()@login_required@check_cache@add_log@permission_verify@transaction.atomicdefinterface_a():所以这里引入一个中间件来处理这个事情,不用每次都额外加代码。中间件操作发生在后端路由调度时。对于每一个请求,我们根据请求的会话找到用户,找到对应的用户组,然后找到权限。将定义的具有权限的模块函数与请求处理程序进行比较。如果它们不同则受到限制。defpermission_middleware():permissions=request.get.user_permissions()if'{}_{}'.format(handler.__class__,handler.func_name)notinpermissions:returnpermission_denied这个后端限制逻辑比较结构化,省了很多麻烦的是方便修改和管理。同时,具有良好的可扩展性。我们将用户定义为单个用户对象,并将权限视为单个处理程序对象。所有门店、部门、集团、小集团等都可以划分到集团层。几乎大部分的业务需求都可以相应的实现。逻辑很准确,好吧,他妈的。受限闭环,对象细化第二天PM来了,说xx部门的小x说他们部门的工作内容需要分类,(我在点头,心里想:嗯,我会的为你的每个类别用户权限添加一个组配置)一个工作类别中有很多工人,并且有一个经理。manager需要查看所有worker的工作进度,job内容manager也可以做(心想:嗯,我就加个manager的组吧,所有权限都一样,单独一个权限查看工作进度)同时!分类1下的管理者也能看到分类2、3下的小y、小z的工作进度!(心想:什么?这不科学吧)PM继续说,因为他们的工作需要衔接,是一个需要查看的功能(我觉得:如果经理不这样就好了’t分类,所有内容都可以看)而且他们也看不到全部!PM继续说,他的主要工作还是这个分类下的工作内容,只是查看其他分类下几个人的进度,你不能给他看所有的内容,有些还是保密的。这确实是个问题,不仅在这种特殊情况下,只要涉及到对某个用户或某个特定内容进行限制操作,就无法实现。辗转反侧后发现,我们之前所做的只是将权限限制在操作行为上,没有形成闭环,也没有定义操作哪些对象。每个限制默认为所有对象。这样虽然方便管理,但是有些场景不能满足需求。因此,引入权限操作对象范围的概念:在之前的权限层上,增加:是否有对象粒度限制,限制哪个模型的对象,可以操作的对象id列表。由于这部分是数据过滤的处理,我们不能在中间件中完成这个操作。把这部分放到数据处理层(DAO层)进行过滤是个不错的主意。首先在数据处理方法中,我们在context中获取本次请求的user对象,按照老方法获取其所有权限。这个时候我们根据我们预先定义的判断:是否有对象粒度限制,限制是根据当前处理的模型过滤掉操作的对象id列表。这样返回数据时,所有的记录都是有操作权限的对象。现在我们满足所有(至少)就是目前遇到的业务需求,后续权限的所有需求也可以按照这个思路配置处理,就可以解决(祝好^_^)前端限制提升体验至此,我们的开发工作会变得很愉快,逻辑清晰,结构严谨,同时给c端用户带来的体验是,哪里都点不进去,点了也不给你,不是不好给个美图或者弹窗,肯定看到403、404或者500的跳转,这时候用户只有一句mmp,再也没有什么破东西了,所以,必须在前端预先限制权限。幸运的是,我们使用大多数情况下使用模板引擎,在页面上判断权限非常方便。在服务器端渲染页面时,根据当前请求用户,获取所有权限,在某个DOM上简单随意写一段判断代码,在流程中放置匹配中间件中handler的过程模板渲染。这样就过滤掉了未经许可的条目,给用户一个安静的世界,也可以避免点击不该点击的东西。{%ifuser.permissions.can_modify_xxx%}
