iT邦幫忙

2021 iThome 鐵人賽

DAY 24
1
自我挑戰組

Python 30天自我挑戰系列 第 24

Day24 - 權限控制

  • 分享至 

  • xImage
  •  

今天的實作內容主要根據教學網站進行。

在Day22時,我們實作了身份驗證功能,部分功能要求使用者必須登入網站才可使用;Day23整合社群登入,提供使用者可選擇以Google帳號進行登入。

截至Day23的內容,我們開發了小說追蹤功能,所有登入者都可以將小說加入追蹤;並提供Book List,所有的登入者都可以看到目前追蹤的小說。

今天我們將實作權限管理,透過權限管理,讓不同的登入者可以使用不同的功能,並在Book List提供僅該登入者追蹤的小說。

我們將使用Django內建的User和Group,透過對於Group授予權限、並將User分配到該Group,來達到此目的。

models.py

新增 User_Book

為了記錄每個使用者各自追蹤的小說,我們新增了User_Book來記錄使用者和小說之間的關係。

class User_Book(models.Model):
  user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
  book = models.ForeignKey(Book, on_delete=models.SET_NULL, null=True)
  notify = models.BooleanField(default=True)

  class Meta:
    ordering = ['book']
    unique_together = [['book', 'user']]

User註冊後自動加入預設群組

Django的signal模組,可支援物件中信息的傳遞。使用此模組,當接收到User建立時,create_user_profile()會將該User加入'Track Members'群組。

from django.contrib.auth.models import User, Group
from django.db.models.signals import post_save

@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
  if created:
    instance.groups.add(Group.objects.get(name='Track Members'))

新增權限 (Permission)

Django提供了很多預設權限可以做選擇,在教學網站中也提供了客製權限的方法。

當我們想要用'can_track'這個權限來控制使用者是否可使用「加入追蹤」功能,只要於Model中的Meta設定permissions,再重新migrate資料庫,就會自動新的權限。

class User_Book(models.Model):
  user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
  book = models.ForeignKey(Book, on_delete=models.SET_NULL, null=True)
  notify = models.BooleanField(default=True)

  class Meta:
    ordering = ['book']
    unique_together = [['book', 'user']]
    permissions = (('can_track', 'Can Track'),)

但依照此方法,每個權限需要與Model進行綁定,這樣會導致該權限會被Model展開,在實際操作時會容易混亂且不方便管理。

舉例來說,對於加入追蹤功能而言,需要同時有Author、Book、User_Book三個Model的權限,若在三個類別各自的Meta下做permission設定,在Group的管理畫面上會出現:

  • track | book | Can Track
  • track | author | Can Track
  • track | user_book | Can Track

對於此問題,可以建立一個空的類別,讓客製權限統一集中在這邊管理。

class RightsSupport(models.Model):
            
  class Meta:        
    # No database table creation or deletion operations will be performed for this model.
    managed = False  
    # disable "add", "change", "delete" and "view" default permissions
    default_permissions = () 
    permissions = ( ('can_track', 'Can Track'), )

管理網站設定群組與權限

登入http://127.0.0.1:8000/admin/,新增「Track Member」Group,並授予「track | rights support | Can Track」權限。

templates

在template中,使用者的權限儲存在「perms」變數中,可以透過此變數來檢查使用者是否有特定權限:

{% if perms.track.can_track %}
<p>有此功能權限。</p>
{% else %}
<p>無此功能權限。</p>
{% endif %}

views.py

根據view是function類型、或class類型,在權限管理上有不同的做法。

class類型

使用合成方法,加入LoginRequiredMixin類別,以設定permission_required屬性;並修改get_queryset()方法,僅查詢當前user加入追蹤的資料。

from django.contrib.auth.mixins import LoginRequiredMixin

class BookListView(LoginRequiredMixin, generic.ListView):
  permission_required = ('track.can_track')

  model = Book
  template_name = 'book_list.html'
    
  def get_queryset(self): 
    return Book.objects.filter(user_book__user=self.request.user, istrack=True)

function類型

使用修飾詞進行權限檢查。

但使用@permission_required()時,若使用者無權限,會自動導到登入畫面,對於已登入的使用者來說此流程比較詭異。 (此問題尚未完成替代方法)

from django.contrib.auth.decorators import login_required, permission_required

@login_required
@permission_required('track.can_track')
def TrackBook(request):
  pass

上一篇
Day23 - 使用Django-allauth整合社群登入
下一篇
Day25 - 使用Django-Q排程
系列文
Python 30天自我挑戰30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言