1. 程式人生 > 程式設計 >Django 許可權管理(permissions)與使用者組(group)詳解

Django 許可權管理(permissions)與使用者組(group)詳解

如果你只是利用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',)

當你使用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,...)

如果你希望在程式碼中移除一個使用者的許可權,你可以使用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',)
  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,...)
mygroup.permissions.remove(permission,...)
mygroup.permissions.clear()

如果你要將某個使用者移除某個使用者組,可以使用如下方法。

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

Django自帶許可權機制的不足

Django自帶的許可權機制是針對模型的,這就意味著一個使用者如果對Article模型有change的許可權,那麼該使用者獲得對所有文章物件進行修改的許可權。如果我們希望實現對單個文章物件的許可權管理,我們需要藉助於第三方庫比如django guardian。至於該庫的使用,我們以後再詳細介紹。

到此這篇關於Django 許可權管理(permissions)與使用者組(group)詳解的文章就介紹到這了,更多相關Django 許可權管理與使用者組內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!