許可(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閱讀 228,546評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,570評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,505評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,017評論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,786評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,219評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,438評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,971評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,796評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,995評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,230評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,918評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,697評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容