Django 用 user吟孙、group 和 permission 完成了權限機制,這個權限機制是將屬于 model 的某個 permission 賦予 user 或 group料按,可以理解為全局的權限。
即如果用戶 A 對數(shù)據(jù)模型(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 項目里創(chuàng)建一個叫 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 會自動創(chuàng)建相應的三個 permission:add_book
炎码、change_book
和 delete_book
。
每個 permission 都是 django.contrib.auth.Permission
類型的實例秋泳,該類型包含三個字段 name
, codename
和 content_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 的 參數(shù)格式是: '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.用戶權限管理
我們再創(chuàng)建一個普通的用戶 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
新創(chuàng)建的普通用戶并沒有對 Book 對象 add和敬、change、delete 的權限戏阅,現(xiàn)在我們來給用戶 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 創(chuàng)建新的權限項:read_book, vote_book(參見豆瓣:讀過、評分)等等芭逝。
現(xiàn)在我們?yōu)?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:
# 自定義的權限,兩參數(shù)分別是權限的名字和權限的描述
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 的 listuser.get_group_permissions()
方法列出用戶所屬 group 的權限胖翰,返回值是 permission name的 list
4.組別(Group)
用戶組模型很簡單接剩,和 User 模型是多對多的關系。用戶組顧名思義泡态,就是對用戶進行了分組搂漠。其作用在權限控制中就是可以批量的對用戶的許可進行分配,而不用一個一個的按用戶分配某弦,節(jié)省維護的工作量桐汤。
將一個用戶加入到一個 Group 中,該用戶就擁有了該 Group 所分配的所有許可靶壮。例如怔毛,如果一個組 reader 有權限 read_book 和 vote_book。那么所有屬于 reader 組的用戶都會有這個權限腾降。
下面我們創(chuàng)建一個新分組 reader拣度,再把某用戶加入到該組,再給該組添加上權限:
# 創(chuàng)建一個分組
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 才訪問該頁面
# 否則跳轉(zhuǎn)到 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
存儲當前用戶的所有權限:
# 以下內(nèi)容只對擁有 vote_book 權限的用戶顯示
{% if perms.myApp.vote_book %}
<button>打分</button>
{% else %}
<p>你不能打分</p>
{% endif %}