Django 权限管理(permissions)与用户组(group)详解


Posted in Python onNovember 30, 2020

如果你只是利用Django开发个博客,大部分用户只是阅读你的文章而已,你可能根本用不到本节内容。但是如果你想开发一个内容管理系统,或用户管理系统,你必需对用户的权限进行管理和控制。Django自带的权限机制(permissions)与用户组(group)可以让我们很方便地对用户权限进行管理。小编我今天就尝试以浅显的语言来讲解下如何使用Django自带的权限管理机制。

什么是权限?

权限是能够约束用户行为和控制页面显示内容的一种机制。一个完整的权限应该包含3个要素: 用户,对象和权限,即什么用户对什么对象有什么样的权限。

假设我们有一个应用叫blog,其包含一个叫Article(文章)的模型。那么一个超级用户一般会有如下4种权限,而一个普通用户可能只有1种或某几种权限,比如只能查看文章,或者能查看和创建文章但是不能修改和删除。

  • 查看文章(view)
  • 创建文章(add)
  • 更改文章(change)
  • 删除文章(delete)

我们在Django的admin中是可以很轻易地给用户分配权限的。

Django Admin中的权限分配

Django中的用户权限分配,主要通过Django自带的Admin界面进行维护的。当你编辑某个user信息时, 你可以很轻易地在User permissions栏为其设置对某些模型查看, 增加、更改和删除的权限(如下图所示)。 

Django的权限permission本质是djang.contrib.auth中的一个模型, 其与User的user_permissions字段是多对多的关系。当我们在INSTALLED_APP里添加好auth应用之后,Django就会为每一个你安装的app中的模型(Model)自动创建4个可选的权限:view, add,change和delete。(注: Django 2.0前没有view权限)。随后你可以通过admin将这些权限分配给不同用户。

查看用户的权限

权限名一般有app名(app_label),权限动作和模型名组成。以blog应用为例,Django为Article模型自动创建的4个可选权限名分别为:

  • 查看文章(view): blog.view_article
  • 创建文章(add): blog.add_article
  • 更改文章(change): blog.change_article
  • 删除文章(delete): blog.delete_article

在前例中,我们已经通过Admin给用户A(user_A)分配了创建文章和修改文章的权限。我们现在可以使用user.has_perm()方法来判断用户是否已经拥有相应权限。下例中应该返回True。

  • user_A.has_perm('blog.add_article')
  • user_A.has_perm('blog.change_article')

如果我们要查看某个用户所在用户组的权限或某个用户的所有权限(包括从用户组获得的权限),我们可以使用get_group_permissions()和get_all_permissions()方法。

  • user_A.get_group_permissions()
  • user_A.get_all_permissions()

手动定义和分配权限(Permissions

有时django创建的4种可选权限满足不了我们的要求,这时我们需要自定义权限。实现方法主要有两种。下面我们将分别使用2种方法给Article模型新增了两个权限,一个是publish_article, 一个是comment_article。

方法1. 在Model的meta属性中添加permissions。

class Article(models.Model):
  ...
  class Meta:
    permissions = (
      ("publish_article", "Can publish article"),
      ("comment_article", "Can comment article"),
    )

方法2. 使用ContentType程序化创建permissions。

from blog.models import Article
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
 
content_type = ContentType.objects.get_for_model(article)
permission1 = Permission.objects.create(
  codename='publish_article',
  name='Can publish articles',
  content_type=content_type,
)
 
permission2 = Permission.objects.create(
  codename='comment_article',
  name='Can comment articles',
  content_type=content_type,
)

当你使用python manage.py migrate命令后,你会发现Django admin的user permissions栏又多了两个可选权限。

如果你不希望总是通过admin来给用户设置权限,你还可以在代码里手动给用户分配权限。这里也有两种实现方法。

方法1. 使用user.user_permissions.add()方法

myuser.user_permissions.add(permission1, permission2, ...)

方法2. 通过user所在的用户组(group)给用户增加权限

mygroup.permissions.add(permission1, permission2, ...)

如果你希望在代码中移除一个用户的权限,你可以使用remove或clear方法。

myuser.user_permissions.remove(permission, permission, ...)
myuser.user_permissions.clear()

注意权限的缓存机制

Django会缓存每个用户对象,包括其权限user_permissions。当你在代码中手动改变一个用户的权限后,你必须重新获取该用户对象,才能获取最新的权限。

比如下例在代码中给用户手动增加了change_blogpost的权限,如果不重新载入用户,那么将显示用户还是没有change_blogpost的权限。

from django.contrib.auth.models import Permission, User
from django.contrib.contenttypes.models import ContentType
from django.shortcuts import get_object_or_404
 
from myapp.models import BlogPost
 
def user_gains_perms(request, user_id):
  user = get_object_or_404(User, pk=user_id)
  # any permission check will cache the current set of permissions
  user.has_perm('myapp.change_blogpost') 
 
  content_type = ContentType.objects.get_for_model(BlogPost)
  permission = Permission.objects.get(
    codename='change_blogpost',
    content_type=content_type,
  )
  user.user_permissions.add(permission)
 
  # Checking the cached permission set
  user.has_perm('myapp.change_blogpost') # False
 
  # Request new instance of User
  # Be aware that user.refresh_from_db() won't clear the cache.
  user = get_object_or_404(User, pk=user_id)
 
  # Permission cache is repopulated from the database
  user.has_perm('myapp.change_blogpost') # True

用户权限的验证(Validation)

我们前面讲解了用户权限的创建和设置,现在我们将进入关键一环,用户权限的验证。我们在分配好权限后,我们还需要在视图views.py和模板里验证用户是否具有相应的权限,否则前面设置的权限形同虚设。这就是为什么我们前面很多django实战案例里,没有给用户分配某个模型的add和change权限,用户还是还能创建和编辑对象的原因。

1. 视图中验证

在视图中你当然可以使用user.has_perm方法对一个用户的权限进行直接验证。当然一个更好的方法是使用@permission_required这个装饰器。

permission_required(perm, login_url=None, raise_exception=False)

你如果指定了login_url, 用户会被要求先登录。如果你设置了raise_exception=True, 会直接返回403无权限的错误,而不会跳转到登录页面。使用方法如下所示:

from django.contrib.auth.decorators import permission_required
 
@permission_required('polls.can_vote')
def my_view(request):
  ...

如果你使用基于类的视图(Class Based View), 而不是函数视图,你需要继承PermissionRequiredMixin这个类,如下所示:

from django.contrib.auth.mixins import PermissionRequiredMixin
 
class MyView(PermissionRequiredMixin, View):
  permission_required = 'polls.can_vote'
  # Or multiple of permissions:
  permission_required = ('polls.can_open', 'polls.can_edit')

2. 模板中验证

在模板中验证用户权限主要需要学会使用perms这个全局变量。perms对当前用户的user.has_module_perms和user.has_perm方法进行了封装。当我们需要判断当前用户是否拥有blog应用下的所有权限时,我们可以使用:

{{ perms.blog }}

我们如果判断当前用户是否拥有blog应用下发表文章讨论的权限,则使用:

{{ perms.blog.comment_article }}

这样结合template的if标签,我们可以通过判断当前用户所具有的权限,显示不同的内容了.

{% if blog.article %}
  <p>You have permission to do something in this blog app.</p>
  {% if perms.blog.add_article %}
    <p>You can add articles.</p>
  {% endif %}
  {% if perms.blog.comment_article %}
    <p>You can comment articles!</p>
  {% endif %}
{% else %}
  <p>You don't have permission to do anything in the blog app.</p>
{% endif %}

用户组(Group)

 用户组(Group)和User模型是多对多的关系。其作用在权限控制时可以批量对用户的权限进行管理和分配,而不用一个一个用户分配,节省工作量。将一个用户加入到一个Group中后,该用户就拥有了该Group所分配的所有权限。例如,如果一个用户组editors有权限change_article, 那么所有属于editors组的用户都会有这个权限。

将用户添加到用户组或者给用户组(group)添加权限,一般建议直接通过django admin进行。如果你希望手动给group添加或删除权限,你可以使用如下方法。

mygroup.permissions = [permission_list]
mygroup.permissions.add(permission, permission, ...)
mygroup.permissions.remove(permission, permission, ...)
mygroup.permissions.clear()

如果你要将某个用户移除某个用户组,可以使用如下方法。

myuser.groups.remove(group, group, ...) #
myuser.groups.clear()

Django自带权限机制的不足

Django自带的权限机制是针对模型的,这就意味着一个用户如果对Article模型有change的权限,那么该用户获得对所有文章对象进行修改的权限。如果我们希望实现对单个文章对象的权限管理,我们需要借助于第三方库比如django guardian。至于该库的使用,我们以后再详细介绍。

到此这篇关于Django 权限管理(permissions)与用户组(group)详解的文章就介绍到这了,更多相关Django 权限管理与用户组内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python之文件的读写和文件目录以及文件夹的操作实现代码
Aug 28 Python
使用Python写CUDA程序的方法
Mar 27 Python
新手常见6种的python报错及解决方法
Mar 09 Python
django数据库自动重连的方法实例
Jul 21 Python
python opencv 简单阈值算法的实现
Aug 04 Python
使用Python自动生成HTML的方法示例
Aug 06 Python
Python生成验证码、计算具体日期是一年中的第几天实例代码详解
Oct 16 Python
Matplotlib使用字符串代替变量绘制散点图的方法
Feb 17 Python
Pytest单元测试框架如何实现参数化
Sep 05 Python
python装饰器代码深入讲解
Mar 01 Python
matplotlib之pyplot模块实现添加子图subplot的使用
Apr 25 Python
pytorch锁死在dataloader(训练时卡死)
May 28 Python
python 如何引入协程和原理分析
Nov 30 #Python
Django缓存Cache使用详解
Nov 30 #Python
Django框架实现在线考试系统的示例代码
Nov 30 #Python
python爬虫 requests-html的使用
Nov 30 #Python
python实现登录与注册系统
Nov 30 #Python
python代码实现图书管理系统
Nov 30 #Python
python 爬虫网页登陆的简单实现
Nov 30 #Python
You might like
PHP安全防范技巧分享
2011/11/03 PHP
实用的简单PHP分页集合包括使用方法
2013/10/21 PHP
PHP简单字符串过滤方法示例
2016/09/04 PHP
php闭包中使用use声明变量的作用域实例分析
2018/08/09 PHP
JS 创建对象(常见的几种方法)
2008/11/03 Javascript
JavaScript Chart 插件整理
2010/06/18 Javascript
javascript 主动派发事件总结
2011/08/09 Javascript
利用Javascript判断操作系统的类型实现不同操作系统下的兼容性
2013/01/29 Javascript
Nodejs+express+html5 实现拖拽上传
2014/08/08 NodeJs
js实现点击添加一个input节点
2014/12/05 Javascript
jQuery应用之jQuery链用法实例
2015/01/19 Javascript
Javascript编写2048小游戏
2015/07/07 Javascript
JS实现支持多选的遍历下拉列表代码
2015/08/20 Javascript
AngularJS基础 ng-mousemove 指令简单示例
2016/08/02 Javascript
Jquery组件easyUi实现选项卡切换示例
2016/08/23 Javascript
值得学习的bootstrap fileinput文件上传工具
2016/11/08 Javascript
jquery.Callbacks的实现详解
2016/11/30 Javascript
JavaScript的事件机制详解
2017/01/17 Javascript
seajs中模块依赖的加载处理实例分析
2017/10/10 Javascript
phantomjs导出html到pdf的方法总结
2017/10/19 Javascript
ReactNative中使用Redux架构总结
2017/12/15 Javascript
vue-cli3+typescript初体验小结
2019/02/28 Javascript
微信小程序canvas绘制圆角base64图片的实现
2019/08/18 Javascript
React学习之JSX与react事件实例分析
2020/01/06 Javascript
解决vue的touchStart事件及click事件冲突问题
2020/07/21 Javascript
JS实现超级好看的鼠标小尾巴特效
2020/12/01 Javascript
[05:08]第一届“网鱼杯”DOTA2比赛精彩集锦
2014/09/05 DOTA
使用Python脚本对Linux服务器进行监控的教程
2015/04/02 Python
Python+selenium 获取一组元素属性值的实例
2018/06/22 Python
python中的decorator的作用详解
2018/07/26 Python
详解Django中views数据查询使用locals()函数进行优化
2020/08/24 Python
详解CSS3阴影 box-shadow的使用和技巧总结
2016/12/03 HTML / CSS
Css3实现无缝滚动防抖
2020/09/14 HTML / CSS
一套软件开发工程师笔试题
2015/05/18 面试题
2014年便民服务中心工作总结
2014/12/20 职场文书
老兵退伍感言
2015/08/03 职场文书