Day24 - 权限控制

今天的实作内容主要根据教学网站进行。

在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

<<:  Swift 新手-运用 Bluetooth Low Energy

>>:  Day 21 中场休息,来做点酷东西(重构 class)

[Day-8] R语言 - K - means 实作 ( K - means in R.Studio)

您的订阅是我制作影片的动力 订阅点这里~ 影片程序码 library(naniar) data(ir...

【Day09】陈述式与表达式

陈述式(Statement) JavaScript 语句类型,用於命令执行指定一系列操作,最大的特徵...

[CSS] Flex/Grid Layout Modules, part 13

单元对齐跟留白的部分今天会继续,定位的问题基本上不出乱子的话就如同昨天说明的。当然,如果再加上对齐跟...

Day.19 认识索引 - 二级索引 (Secondary Index)

InnoDB将索引分成Cluster Index & Secondary Index,认识...

Proxmox VE 虚拟机管理操作 (二)

虚拟机的建置与操作已经来到基本使用的程度了,对於各种应用修改与尝试後可能伴随虚拟机被搞砸的风险。 ...