许可(Permissions)和用户组(Group)

Django 用 user、group 和 permission 完成了权限机制,这个权限机制是将属于 model 的某个 permission 赋予 user 或 group,可以理解为全局的权限

即如果用户 A 对数据模型(model)B 有可写权限,那么 A 能修改 model B 的所有实例(objects)。group 的权限也是如此,如果为 group C 赋予 model B 的可写权限,则隶属于 group C 的所有用户,都可以修改 model B 的所有实例。




1.Django的权限项

Django 用 permission 对象存储权限项,每个 model 默认都有三个 permission,即 add、change 和 delete。

我们在 Django 项目里创建一个叫 myApp 的 app,然后在 modles 添加一个 Book 模型:

from django.db import models

class Book(models.Model):
    title = models.CharField(null=True, blank=True, max_length=200)

    def __str__(self):
        return self.title

打开 admin 可以在 user 的管理界面看到 Book 的三个 permission:

因为在定义好 Book 之后,Django 会自动创建相应的三个 permission:add_bookchange_bookdelete_book

每个 permission 都是 django.contrib.auth.Permission 类型的实例,该类型包含三个字段 name, codenamecontent_type

  • content_type 反应了 permission 属于哪个 model(如:Book)
  • codename 是代码逻辑中检查权限时要用(如:'add_book')
  • name 是 permission 的描述,将 permission 打印到屏幕或页面时默认显示的就是name(如:Can add book)

我们可以用 has_perm() 方法来检验某个用户是否用于某种权限:

from django.contrib.auth.models import User

u = User.objects.get(username='diego')

# has_perm 的 参数格式是: 'app_label.codename'
>>> u.has_perm('myApp.add_book')
True

>>> u.has_perm('myApp.change_book')
True

>>> u.has_perm('myApp.delete_book')
True

可见超级用户 diego 拥有对 Book 模型的所有对象进行 add、change、delete 操作的权限。




2.用户权限管理

我们再创建一个普通的用户 test_user,然后检测下它的权限:

u = User.objects.get(username='test_user')

>>> u.has_perm('myApp.add_book')
False

>>> u.has_perm('myApp.change_book')
False

>>> u.has_perm('myApp.delete_book')
False

新创建的普通用户并没有对 Book 对象 add、change、delete 的权限,现在我们来给用户 test_user 增加权限:

# 用户模型、权限模型
from django.contrib.auth.models import User, Permission

u = User.objects.get(username='test_user')

# 通过 codename 找到对应的权限
permission = Permission.objects.get(codename='change_book')

# 把权限赋予给该用户
u.user_permissions.add(permission)

>>> u.has_perm('myApp.change_book')
True

同理,还可以对用户权限进行其他操作:

# 设置权限
myuser.user_permissions = [permission_list]

# 设置权限
myuser.user_permissions.set([permission_list])

#增加权限
myuser.user_permissions.add(permission, permission, ...)

#删除权限
myuser.user_permissions.remove(permission, permission, ...) 

#清空权限
myuser.user_permissions.clear()


# 注意:myuser 是一个用户对象,permission 是一个权限对象




3.自定义权限

Django 还允许自定义 permission,例如,我们可以为 Book 创建新的权限项:read_book, vote_book(参见豆瓣:读过、评分)等等。

现在我们为 Book 模型增加两项新的 permission,分别为 read_book 和 vote_book:

from django.db import models

class Book(models.Model):
    title = models.CharField(null=True, blank=True, max_length=200)

    def __str__(self):
        return self.title

    class Meta:
        # 自定义的权限,两参数分别是权限的名字和权限的描述
        permissions = (
            ("read_book", "Can Read Book"),
            ("vote_book", "Can Vote Book"),
        )

再打开 admin 检查,可以看到刚才新增加的:

再做个测试:

u = User.objects.get(username='diego')

>>> u.has_perm('myApp.read_book')
True

>>> u.has_perm('myApp.vote_book')
True

超级管理员同样拥有新增加的 permission。

附注:

  • user.get_all_permissions() 方法列出用户的所有权限,返回值是 permission name 的 list

  • user.get_group_permissions() 方法列出用户所属 group 的权限,返回值是 permission name的 list




4.组别(Group)

用户组模型很简单,和 User 模型是多对多的关系。用户组顾名思义,就是对用户进行了分组。其作用在权限控制中就是可以批量的对用户的许可进行分配,而不用一个一个的按用户分配,节省维护的工作量。

将一个用户加入到一个 Group 中,该用户就拥有了该 Group 所分配的所有许可。例如,如果一个组 reader 有权限 read_book 和 vote_book。那么所有属于 reader 组的用户都会有这个权限。

下面我们创建一个新分组 reader,再把某用户加入到该组,再给该组添加上权限:

# 创建一个分组
Group.objects.create(name='reader')

# 获取某用户
u = User.objects.get(username='test_user')

# 获取某分组
g = Group.objects.get(name='reader')

# 把用户加入到分组中
u.groups.add(g)

# 获取某个权限
p= Permission.objects.get(codename='read_book')

# 把该权限加入到分组
g.permissions.add(p)

Group 还有其他操作:

# 把用户加入分组,group_list可以是一个或多个分组
u.groups = [group_list]

# 把用户加入某分组
u.groups.add(group, group, ...)

# 把某用户从某分组删除
u.groups.remove(group, group, ...)

# 该用户退出所以分组
u.groups.clear()

# 把权限加入到该分组
g.permissions.add(permission, permissions, ...)

# 从该分组删除某权限
g.permissions.remove(permission, permissions, ...)

# 清除该分组所以权限
g.permissions.clear()




5.permission_required 装饰器

使用了permission_required 装饰器之后,Django 会检查用户是否拥有指定的 permission,有相应 permission 的用户才能访问该页面:

from django.contrib.auth.decorators import permission_required

# 图书阅览页面
# 需要有权限 book.read_book 才访问该页面
# 否则跳转到 user_login 页
@ permission_required(perm='book.read_book', login_url="/user_login/")
def read_book(request, id):
    context = {}
    book = Book.objects.get(id=id)
    context['book'] = book
    return render(request, 'read_book.html', context) 




6.Template 中的权限检查

Template 中使用全局变量 perms 存储当前用户的所有权限:

# 以下内容只对拥有 vote_book  权限的用户显示
{% if perms.myApp.vote_book %}
    <button>打分</button>
{% else %}
    <p>你不能打分</p>
{% endif %}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容