在 django orm 里面加上权限控制

2021-06-17 13:18:25 +08:00
 chaleaoch
需求是这样的:
我需要对一些资源(其实就是一些 model 表)的权限做一些限制.
但是这些限制无法直接加在 api 上.
譬如关联表啊 什么的. 需要考虑的情况比较复杂.


所以我在想能不能 在 model 和 manager 上做文章. 譬如 model.objects.filter(**kwargs) 的时候报错 instance.save()的时候报错.

自定义 当然没问题.

我的问题是, 都有哪些 orm 的 api 会动表数据啊. 这就比较难受了. 不太好统计啊.


各位大佬可有良策......


谢谢大佬.
1666 次点击
所在节点    Python
13 条回复
chi1st
2021-06-17 14:01:57 +08:00
没完全理解你的意思,不知道 signal 能不能解决你的问题
dayeye2006199
2021-06-17 15:01:56 +08:00
看你要对 表 进行权限控制,还是对 行 进行控制。

全面这个情况用 django 内置的 permission 体系就可以完成,can_view, can_edit, can_delete 之类的权限 associate 到用户身上就行了。

后面这个情况没有开箱即用的方案,用的比较多的是这个第三方包: https://github.com/django-guardian/django-guardian
wellsc
2021-06-17 15:05:40 +08:00
报错?报什么错?把客观原因找出来
chaleaoch
2021-06-17 15:14:27 +08:00
@dayeye2006199 啊 我不是这个意思..

你的方法是在应用层 每次对数据库进行操作之前先判断一下 是否有权限.

我是想 不在应用层做, 就在 orm 里面把权限校验给做了.
a719114136
2021-06-17 17:53:10 +08:00
1. 所有 db 操作通过函数封装一层,然后在函数里控制。

2.重写 manage,至于操作函数也就那几个( filter, get, all, create, save, count ...) ,再底层可能有统一的入口函数,只能自己找找看
Vegetable
2021-06-17 19:23:32 +08:00
我也有一阵子没写 Django 了,不过还能扯两句。

你的思路问题不大,因为动表的 api 真的很少。实例的 save 、delete,和 manager 的 delete 、bulk_create 、bulk_update 。
https://docs.djangoproject.com/en/3.2/ref/models/querysets/

前两个很好操作,你可以直接在 model 上修改,三年前我写过一篇相关的内容,不过当时是记录操作日志,不是权限控制 https://segmentfault.com/a/1190000015022691 当初也是年轻哈哈写的什么玩意

manager 方法大部分会调用 model 的 save,但是批量操作的都不会,也就是 delete\bulk_create\bulk_update 。如果你想让别人用的爽一点,这里就得多做点工作。

判断权限需要得到当前登录的用户,这一点其实挺烦的,Django 没有 flask 的 g,orm 层也没有请求上下文,你通过什么办法在 orm 层面得到请求上下文?这也是你需要解决的问题

related: https://stackoverflow.com/questions/3227180/why-is-using-thread-locals-in-django-bad
Vegetable
2021-06-17 19:27:46 +08:00
你好像还提到了读操作,读操作思路没研究过,不过读操作限制起来终究是简单一点,比如你可以在 model 的__init__阶段判断当前用户有没有权限获取这个实例,想读就一定需要实例化嘛。
不过这种方式局限性也很大,还是得根据项目判断。
lybcyd
2021-06-17 20:34:22 +08:00
你的思路可以实现,自定义 manager 、queryset 和 model,覆盖 crud 方法就可以。或者用 signal 实现。注意自带的批量不会触发这些方法,所以要单独处理。

不过我觉得权限放在 orm 这层可能不是个好主意,以后修改维护都不太方便,orm 应该只关注查询,加太多功能就太臃肿了。为什么不能放在视图层?这个是最自然的解决方案,根据请求和 user 直接判断,也好维护。
abersheeran
2021-06-17 21:19:15 +08:00
显然,Django 的设计无法解决这个问题。权限跟用户有关系,用户只能从 request 对象拿。你用什么方式把 request 传进 ORM 里?
chaleaoch
2021-06-17 21:30:21 +08:00
@lybcyd 因为我使用了大量的 viewset. 而权限控制是后加的功能.(之前是由 kong 来控制的)

如果在 api 层(就是您说的视图层)控制,那有大量代码需要修改.
另外 我这个项目业务逻辑很诡异. 在视图层做. 一不小心就容易出 bug.
freakxx
2021-06-17 21:39:09 +08:00
感觉这么做的话,得重写方法,在里面再做一层定义,但应该是挺棘手的。

比如上面说的 django-guardian,你模仿它的做法,然后在对应的 orm crud 方法,做一层判断;

需要判断的信息放进 context 带过去就试试;
37Y37
2021-06-18 10:37:14 +08:00
换个思路,看看是否可以考虑根据 URL 来做权限控制?大概 6 年前写过一个简单的 demo 可以看看 https://gitee.com/ops-coffee/sadmin
rationa1cuzz
2021-06-18 14:13:31 +08:00
重写或者封装 orm 吧

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/783947

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX