在Django中管理用户权限的教程

1,207 阅读7分钟

所有的应用程序都需要某种检查或权限,以控制每个用户可以做什么,并确定用户是否经过认证。 在这篇文章中,你将学习如何设置多个用户角色,以及如何根据用户角色来设置用户权限。此外,我将说明如何使用Django内置的Users and Groups来为多个用户应用权限。 虽然很多文章只涉及用户权限和默认的Django用户权限,但我将更进一步,建立一个具有不同用户角色的应用程序,然后根据用户的角色来设置权限。

前提条件

要学习这篇文章,需要具备以下条件:

  • 对Django和Python有初步的工作经验
  • 安装了Python 3.7或更高版本

使用Django的内置权限

默认情况下,Django提供了一个内置的授权(permissions)。这个功能使你能够定义每个用户被允许执行的动作。该框架包括UsersGroups 的内置模型,用于为一组用户提供权限,指定用户是否可以执行任务的权限/标志,限制内容的视图工具等。当django.contrib.auth 列在你的INSTALLED_APPS ,它将提供四个默认的权限--添加、更改、删除和每个模型的视图。 现在,让我们假设你有一个项目,有一个应用程序product 和一个模型Order 。为了测试哪些用户有基本权限,你可以使用以下代码:

python manage.py shell
user = User.objects.first()
  • 添加: user.has_perm('product.add_order')
  • 改变: user.has_perm('product.change_order')
  • delete: 删除。 user.has_perm('product.delete_order')
  • view: user.has_perm('product.view_order') 通过使用Django内置的装饰器 permission_required ,可以添加权限,将一个函数限制在只有拥有该特定权限的用户身上。
from django.contrib.auth.decorators import permission_required

@permission_required('product.change_name')
def admin_view(request):
    """Raise permission denied exception or redirect user"""

如果你使用的是基于类的视图,你只需要使用一个混合素,PermissionRequiredMixin

from django.contrib.auth.mixins import PermissionRequiredMixin
from django.views.generic import ListView

class ProductListView(PermissionRequiredMixin, ListView):
    permission_required = 'product.change_name'

如何向模型添加自定义权限

如果权限没有在视图中说明,你可以在你的模型中指定它们。附加权限是在模型的class Meta ,使用权限字段来完成。你将能够根据你的需要指定尽可能多的权限,但它必须是一个元组。例如,你可以定义一个权限,允许用户像这样改变产品的名称。

from django.db import models

class Product(models.Model):
    user = models.ForeignKey(User)    
    class Meta:
        permissions = (("change_name", "can change name of product"),)

为了实现这些变化,运行python manage.py makemigrationsmigrate

如何向模板添加自定义权限

用户的权限可以通过在模板中调用{{ perms }} 来检索。要检查一个特定的用户是否有查看模板的权限,你所要做的就是从持有权限的特定模型中获取perms 。它应该看起来像这样。

{{ perms.<name_of_app>.<permission>}} 例如,{{ perms.app.change_name }} 。通过 if语句,你可以为你的模板的特定部分添加一个权限。

{% if perms.app.change_name %}
<p>can change name of product</p>

{% endif %}

通过这样做,只有拥有change_name 权限的用户才能使用模板的那个特定部分。

如何为视图添加自定义权限

就像你在使用内置的Django权限时一样,你也可以通过使用permission_required 装饰器向视图添加自定义权限,或者在基于类的视图中,使用PermissionRequiredMixin 。 对于基于函数的视图:

from django.contrib.auth.decorators import permission_required

@permission_required('app.change_name')
def the_view(request):
    ...

对于基于类的视图:

from django.contrib.auth.mixins import PermissionRequiredMixin

class MyView(PermissionRequiredMixin, View):
    permission_required = 'app.change_name'
    # Or multiple permissions
    permission_required = ('app.change_name', 'app.edit_name')
    # Note that 'catalog.can_edit' is just an example, you can replace it with
    # whatever permissions you have created

注意

如果一个用户不被允许访问一个view ,并且他们试图访问它,PermissionRequiredMixin@permission_required 的行为是不同的。@permission_required 重定向到登录屏幕,PermissionRequiredMixin 返回HTTP 403 (Status Forbidden) 如果一个用户已经登录但没有正确的权限。

在构建应用程序时,PermissionRequiredMixin 的默认行为是最佳的。要在基于函数的视图中复制这种行为,你必须添加@login_required 装饰器,并将@permission_requiredraise_exception=True 。这就是它的外观:

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

@login_required
@permission_required('app.change_name', raise_exception=True)
def the_view(request):
    ...

为多个用户类型添加权限

通常,当你要实现多个用户类型时,你需要确保每个用户类型都有一些限制。例如,如果你正在建立一个作业应用程序,教师可以设置问题,学生只能回答问题。在这种情况下,你必须设置权限系统,使学生不能选择设置问题。为了说明这一点,让我们假设你试图建立一个应用程序,其中经过认证的教师可以创建作业,经过认证的学生可以回答问题。 假设我们的models.py 文件是这样的:

from django.contrib.auth.models import AbstractUser
from django.db import models

**class** **User**(AbstractUser):
    is_student **=** models**.**BooleanField(default**=**False)
    is_teacher **=** models**.**BooleanField(default**=**False)

**class** **Student**(models**.**Model):
    user **=** models**.**OneToOneField(User, on_delete**=**models**.**CASCADE, primary_key**=**True)
    subjects **=** models**.**ManyToManyField(Subject, related_name**=**'subject')

为了处理这些不同用户的权限,你需要创建一个你自己的自定义装饰器:

# decorator.py

from django.contrib.auth import REDIRECT_FIELD_NAME
from django.contrib.auth.decorators import user_passes_test

def for_students(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url='login'):
    '''
    A decorator to check logged in user could be a student and redirects to the login page if the user isn't authenticated.
    '''
    actual_decorator = user_passes_test(
        lambda u: u.is_active and u.is_student,
        login_url=login_url,
        redirect_field_name=redirect_field_name
    )
    if function:
        return actual_decorator(function)
    return actual_decorator

def for_teachers(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url='login'):
    '''
    A decorator to check whether the logged-in user is a teacher and 
    redirect to the login page if the user is not authenticated.
    '''
    actual_decorator = user_passes_test(
        lambda u: u.is_active and u.is_teacher,
        login_url=login_url,
        redirect_field_name=redirect_field_name
    )
    if function:
        return actual_decorator(function)
    return actual_decorator-

现在,要在视图中使用它们,你所需要做的就是像以前那样调用它。它应该看起来像这样:

# views.py 
from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404
from .decorators import for_students, for_teachers
from .models import Assignment #this is an assumption

@login_required
@student_required  # <-- here is the decorator
def answer_assignment(request, pk):
    quiz = get_object_or_404(Assignment, pk=pk)
    student = request.user.student

    # body of the view...

如果你使用的是基于类的视图,你的视图将看起来像这样:

from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required
from .decorators import for_students

@method_decorator([login_required, student_required], name='dispatch')
class AnswerAssignment(CreateView):

    # body of the view...

向一个组添加权限

值得庆幸的是,Django让你很容易通过默认提供的管理面板来创建组。 本节将包含一个关于你如何在你的应用程序中为组添加权限的说明。让我们假设你正在建立一个提供房地产建议的网站,如果一个用户订阅了 "Tier 1",他们可以查看3个建议,而 "Tier 2 "可以查看6个建议。 考虑到上述情况,你的models.py 文件将看起来像这样:

from django.contrib.auth.models import AbstractUser
from django.db import models


class User(AbstractUser):
    first_name = models.CharField(blank = True, max_length = 20)                      
    last_name = models.CharField(blank = True, max_length = 20)                      
    # You can add more User fields as required

    # define the custom permissions
    # related to User.
    class Meta:
        permissions = (("tier_1", "Can view 3 suggestions"), ("tier_2", "Can view 6 suggestions"),
        # You can add other custom permissions as required
        )

如果你在Django中使用AbstractUser ,你必须添加AUTH_USER_MODEL = 'YourAppName.YourClassName' 。这样,你就告诉Django使用我们的自定义用户模型,而不是默认的。下面的代码应该放在你的admin.py 文件中,这样你就可以看到你的用户模型。

from django.contrib import admin
from .models import User

admin.site.register(User)

为了实现这些变化,运行$ python manage.py makemigrations$ python manage.py migrate 。 接下来,你将创建一个超级用户,用来创建组。要做到这一点,运行$ python3 manage.py createsuperuser ,并填写必要的细节。 现在,用$ python manage.py runserver ,运行你的服务器,并前往管理员,用你刚刚创建的用户细节登录。这是登录后你应该看到的:Image of admin page接下来你要做的是点击 "Group"行的 "+ Add"按钮。 你会被提示一个看起来像这样的表格:

Image of group form

你会看到,你可以选择各种权限,并将它们附加到一个特定的组。

总结

这篇文章的目的是让你从不知道如何在Django应用程序中管理权限到向你展示在构建Django应用程序时可以操作和管理权限的不同方式。希望我能够做到这一点。通过这篇文章,你应该已经学会了如何向视图、模型和模板添加权限。我还展示了你如何能够潜在地创建你自己的自定义权限。最后,我还展示了如何使用Django管理面板向组添加权限。现在你已经学会了所有这些,希望你能够在你未来的Django项目中开始实施这些知识。