django自带权限机制
1. Django权限机制概述
权限机制能够约束用户行为,控制页面的显示内容,也能使API更加安全和灵活;用好权限机制,能让系统更加强大和健壮。因此,基于Django的开发,理清Django权限机制是非常必要的。
1.1 Django的权限控制
Django用user, group和permission完成了权限机制,这个权限机制是将属于model的某个permission赋予user或group,可以理解为全局的权限,即如果用户A对数据模型(model)B有可写权限,那么A能修改model B的所有实例(objects)。group的权限也是如此,如果为group C 赋予model B的可写权限,则隶属于group C 的所有用户,都可以修改model B的所有实例。
这种权限机制只能解决一些简单的应用需求,而大部分应用场景下,需要更细分的权限机制。以博客系统为例,博客系统的用户可分为『管理员』、『编辑』、『作者』和『读者』四个用户组;博客系统管理员和编辑具有查看、修改和删除所有的文章的权限,作者只能修改和删除自己写的文章,而读者则只有阅读权限。管理员、编辑和读者的权限,我们可以用全局权限做控制,而对于作者,全局权限无法满足需求,仅通过全局权限,要么允许作者编辑不属于自己的文章,要么让作者连自己的文章都无法修改。
上述的应用场景,Django自带的权限机制无法满足需求,需要引入另一种更细的权限机制:对象权限(object permission)
。
Object Permission是一种对象颗粒度上的权限机制,它允许为每个具体对象授权。仍沿用最开始的例子,如果model B有三个实例 B1,B2 和B3,如果我们把B1的可写权限赋予用户A,则A可以修改B1对象,而对B2,B3无法修改。对group也一样,如果将B2的可写权限赋予group C,则隶属于group C的所有用户均可以修改B2,但无法修改B1和B3。结合Django自带权限机制和object permission,博客系统中作者的权限控制迎刃而解:系统全局上不允许作者编辑文章,而对于属于作者的具体文章,赋予编辑权限即可。
Django其实包含了object permission的框架,但没有具体实现,object permission的实现需要借助第三方appdjango-guardian,我们在开发中用调用django guradian封装好的方法即可。
1.2 Django的权限项
Django用permission对象存储权限项,每个model默认都有三个permission,即add model, change model和delete model。例如,定义一个名为『Car』model,定义好Car之后,会自动创建相应的三个permission:add_car
, change_car
和delete_car
。Django还允许自定义permission,例如,我们可以为Car创建新的权限项:drive_car
, clean_car
, fix_car
等等
需要注意的是,permission总是与model对应的,如果一个object不是model的实例,我们无法为它创建/分配权限。
2. Django 自带权限机制的应用
2.1 Permission
如上文所述,Django定义每个model后,默认都会添加该model的add, change和delete三个permission,自定义的permission可以在我们定义model时手动添加:
class Task(models.Model):
...
class Meta:
permissions = (
("view_task", "Can see available tasks"),
("change_task_status", "Can change the status of tasks"),
("close_task", "Can remove a task by setting its status as closed"),
)
每个permission都是django.contrib.auth.Permission
类型的实例,该类型包含三个字段name
, codename
和 content_type
,其中 content_type
反应了permission属于哪个model,codename
如上面的view_task
,代码逻辑中检查权限时要用, name
是permission的描述,将permission打印到屏幕或页面时默认显示的就是name
在model中创建自定义权限,从系统开发的角度,可理解为创建系统的内置权限,如果需求中涉及到用户使用系统时创建自定义权限,则要通过下面方法:
from myapp.models import BlogPost
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
content_type = ContentType.objects.get_for_model(BlogPost)
permission = Permission.objects.create(codename='can_publish',
name='Can Publish Posts',
content_type=content_type)
2.2 User Permission管理
User对象的user_permission字段管理用户的权限:
myuser.user_permissions = [permission_list]
myuser.user_permissions.add(permission, permission, ...) #增加权限
myuser.user_permissions.remove(permission, permission, ...) #删除权限
myuser.user_permissions.clear() #清空权限
##############################################################
# 注:上面的permission为django.contrib.auth.Permission类型的实例
##############################################################
检查用户权限用has_perm()
方法:
myuser.has_perm('myapp.fix_car')
has_perm()
方法的参数,即permission的codename
,但传递参数时需要加上model 所属app的前缀,格式为<app label>.<permission codename>
。
无论permission赋予user还是group,has_perm()
方法均适用
附注:
user.get_all_permissions()
方法列出用户的所有权限,返回值是permission name的list
user.get_group_permissions()
方法列出用户所属group的权限,返回值是permission name的list
2.3 Group Permission管理
group permission管理逻辑与user permission管理一致,group中使用permissions字段做权限管理:
group.permissions = [permission_list]
group.permissions.add(permission, permission, ...)
group.permissions.remove(permission, permission, ...)
group.permissions.clear()
权限检查:
依然使用user.has_perm()
方法。
2.4 permission_required
装饰器
权限能约束用户行为,当业务逻辑中涉及到权限检查时,decorator能够分离权限验证和核心的业务逻辑,使代码更简洁,逻辑更清晰。permission的decorator为permission_required
:
from django.contrib.auth.decorators import permission_required
@permission_required('car.drive_car')
def my_view(request):
...
2.5 Template中的权限检查
Template中使用全局变量perms
存储当前用户的所有权限,权限检查可以参考下面例子:
{% if perms.main.add_page %}
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">Pages <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="{% url 'main:admin_pages' %}">All Pages</a></li>
<li><a href="{% url 'main:admin_page' %}">New Page</a></li>
<li><a href="{% url 'main:admin_pages' %}?draft=true">Drafts</a></li>
</ul>
</li>
{% endif %}
3. 基于Django-guardian的object permission的应用
Django-guardian基于django的原生逻辑扩展了django的权限机制,应用django-guardian后,可以使用django-guardian提供的方法以及django的原生方法检查全局权限,django-guardian提供的object permission机制使django的权限机制更加完善。
django-guardian详细的使用文档请参考官方文档,其object permission常用方法如下:
from guardian.shortcuts import assign_perm, get_perms
from guardian.core import ObjectPermissionChecker
from guardian.decorators import permission_required
3.1 添加object permission
添加object permission使用assign_perm()
方法,如为用户添加对mycar对象的drive_car权限:
assign_perm('myapp.drive_car', request.user, mycar)
assign_perm()
方法也可用于group
assign_perm('myapp.drive_car', mygroup, mycar)
3.2 权限检查
3.2.1 Global permission
get_perms()
方法用于检查用户的“全局权限”(global permission),与user.has_perm()
异曲同工,如:
#############################
# It works!
#############################
if not 'main.change_post' in get_perms(request.user, post):
raise HttpResponse('Forbidden')
#############################
# It works, too!
#############################
if not request.user.has_perm('main.change_post')
return HttpResponse('Forbidden')
例子中虽然把post object作为参数传给get_perms()方法,但它只检查user的全局权限中是否有main.change_post
权限,很多情况下可用原生的user.has_perm
取代,但user和group均可作为get_perms()
的传入参数,某些情况下可以使代码更简洁。
3.2.2 Object permission
Django-guardian中使用ObjectPermissionChecker
检查用户的object permission,示例如下:
checker = ObjectPermissionChecker(request.user)
print checker.has_perm('main.change_post', post)
3.3 permission_required装饰器
guardian.decorators.permission_required
是django-guardian权限检查的decorator,既可以检查全局权限,又可以检查对象权限(object permission),其中,accept_global_perms
参数指出是否检查user的global permission,如:
from guardian.decorators import permission_required
class DeletePost(View):
@method_decorator(permission_required('main.delete_post',
(models.Post, 'id', 'pk'),
accept_global_perms=True))
def get(self, request, pk):
try:
pk = int(pk)
cur_post = models.Post.objects.get(pk=pk)
is_draft = cur_post.is_draft
url = reverse('main:admin_posts')
if is_draft:
url = '{0}?draft=true'.format(url)
cur_post.delete()
except models.Post.DoesNotExist:
raise Http404
return redirect(url)
注:
decorator中的(models.Post, 'id', 'pk')
部分,用于指定object实例,如果忽略这个参数,则不论accept_global_perms值为True还是False,均仅仅检查全局权限。
4. 结论
Django原生提供了一种简单的全局权限(global permission)控制机制,但很多应用场景下,对象权限(object permission)更加有用;django-guardian是目前比较活跃的一个django extension,提供了一种有效的object permission控制机制,与django原生机制一脉相承,推荐使用。
作者:Gevin
链接:https://www.jianshu.com/p/01126437e8a4
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
django自带权限机制的更多相关文章
- django自带权限控制系统的使用和分析
1.django的权限控制相关表及其相互间的关系: django的所有权限信息存放在auth_permission表中,用户user和用户组group都可以有对应的权限permission.分别存放在 ...
- python 学习笔记十八 django深入学习三 分页,自定义标签,权限机制
django Pagination(分页) django 自带的分页功能非常强大,我们来看一个简单的练习示例: #导入Paginator>>> from django.core.p ...
- Django权限机制的实现
Django权限机制的实现 1. Django权限机制概述 权限机制能够约束用户行为,控制页面的显示内容,也能使API更加安全和灵活:用好权限机制,能让系统更加强大和健壮.因此,基于Django的开发 ...
- Django默认权限机制介绍及实践
演示Django版本为当前最新版本v2.2 当Django配置文件中的INSTALL_APPS包含了django.contrib.auth时,就默认启用了一个简单的权限系统,提供了为用户或组分配权限的 ...
- django中的权限控制(form增删改)
Django默认提供了权限控制,但只能对使用了其自带的登录认证的用户进行权限控制,说白了就是只能对存储在auth_user表中的用户进行权限控制,但不能对未登录过的用户进行权限控制.但如果通过集成LD ...
- Django自带表User认证详解
认证登陆(附方法实现代码,百度网盘拉取即可下载,激活码:gqt1) 在进行用户登陆验证的时候,如果是自己写代码,就必须要先查询数据库,看用户输入的用户名是否存在于数据库中: 如果用户存在于数据库中,然 ...
- Android权限管理之Permission权限机制及使用
前言: 最近突然喜欢上一句诗:"宠辱不惊,看庭前花开花落:去留无意,望天空云卷云舒." 哈哈~,这个和今天的主题无关,最近只要不学习总觉得生活中少了点什么,所以想着围绕着最近面试过 ...
- Django中的权限系统
Django中已经为我们设置好了基本的权限系统,在定义好model同步数据库后,在每个库下面都会有一张 'auth_permission' 表.该表里面记录了每条权限的描述(name字段,can do ...
- Salesforce的数据权限机制
本文主要介绍了 Salesforce 对于系统中数据的访问控制是如何设计的,然后也了解了下 Alfresco 和 Oracle VPD 的数据权限机制.希望对一些业务系统的数据权限的访问控制设计能有所 ...
随机推荐
- oracle当前月添加一列显示前几个月的累计值
create table test_leiji(rpt_month_id number(8), current_month NUMBER(12,2)); ...
- json_encode用法
1.从数据库中查询出来的数据,放在数组中 $query=mysql_query($SQL); while($row = mysql_fetch_array($query)){ $xda ...
- 前端架构一之XAMPP
摘要: 随着用户体验的重要性和项目的富客户端化,越来越多的公司将前端与后端分离开来,这时候前端就需要有自己的服务环境.本文将介绍我在开发中所用到的前端服务环境的搭建. 环境: OS: win7 64b ...
- Landpy.ActiveDirecoty,按照Active Record Pattern设计的方便Lib开源发布
想方便的操作AD吗,不想记住那么多AD Attribute名称和常量?请使用Landpy.ActiveDirecoty库,按照Active Record Pattern设计的AD Lib已经在Code ...
- mybatis由浅入深day02_4多对多查询_多对多查询总结
4 多对多查询 4.1 需求(查询用户及用户购买商品信息) 查询用户及用户购买商品信息. 4.2 sql语句 查询主表是:用户表 关联表:由于用户和商品没有直接关联,通过订单和订单明细进行关联,所以关 ...
- RIDE指定log和report的输出目录
在命令行中,输入 pybot --help就可以看到他支持的所以命令和相关的介绍 我们可以看到outputdir这个命令,就是来知道report和log的输出目录的 如果你是在命令行中,那么直接后面跟 ...
- Redis(八)-- Redis分布式锁实现
一.使用分布式锁要满足的几个条件 系统是一个分布式系统(关键是分布式,单机的可以使用ReentrantLock或者synchronized代码块来实现) 共享资源(各个系统访问同一个资源,资源的载体可 ...
- 我们复习.Net的这些日子里
今天是我们复习前面学习的第三天,也是在今天我们结束了复习.之前上学时间感觉知识全是生僻的,在生活中很少用到,因此喜欢重复的记忆,而现在学习的知识全是现在乃至未来,将是每天我们使用的,所以就感觉没必要重 ...
- js array.filter实例(数组去重)
语法: 循环对数组中的元素调用callback函数, 如果返回true 保留,如果返回false 过滤掉, 返回新数组,老数组不变 var new_array = source_array.filt ...
- 《C#高级编程》学习笔记------抗变和协变
1.协变和抗变 在.NET 4之前,泛型接口是不变的..NET 4通过协变和抗变为泛型接口和泛型委托添加了一个重要的扩展.协变和抗变指对参数和返回值的类型进行转换.例如,可以给一个需要Shape参数的 ...