django DRF 组件 认证 权限

 

 

我们创建一个新的子应用 component

python manage.py startapp component

 

component/urls.py,子路由代码:

from django.urls import path
from . import views

urlpatterns = [
    
]

注册子应用,settings.py,代码:

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'rest_framework',

    'stuapi',    # 不使用drf编写api接口
    'students',  # 使用了drf编写api接口
    'sers',      # 演示序列化的使用
    'req',       # drf提供的http请求与响应
    'demo',      # drf提供的提供的视图类
    'component', # drf提供的组件功能
]

总路由,代码:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include("stuapi.urls")),
    path('api/', include("students.urls")),
    path('sers/', include("sers.urls")),
    path("req/", include("req.urls")),
    path("demo/", include("demo.urls")),
    path("component/", include("component.urls")),
]

因为接下来的认证组件中需要使用到登陆功能,所以我们使用django内置admin站点并创建一个管理员.

admin运营站点的访问地址:http://127.0.0.1:8000/admin

python manage.py createsuperuser
# 如果之前有账号,但是忘了,可以通过终端下的命令修改指定用户的密码,这里的密码必须8位长度以上的
python manage.py changepassword 用户名

 

 

python manage.py createsuperuser
Username (leave blank to use 'administrator'): root
Email address: 
Password:
Password (again):
This password is too common.
This password is entirely numeric.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.

 

创建管理员以后,访问admin站点,先修改站点的语言配置

settings.py

LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

 

 

 

访问admin 站点效果:

 

 

 

 

 

认证Authentication

可以在配置文件中配置全局默认的认证方式/认证方案。

开发中常见的认证方式:cookie、sessiontoken

rest_framework/settings.py 默认配置文件

REST_FRAMEWORK = {
    # 配置认证方式的选项
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication', # session认证
        'rest_framework.authentication.BasicAuthentication',   # basic认证[基于账号密码]
    )
}

可以在具体的视图类中通过设置类属性authentication_classess来设置单独的不同的认证方式

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import SessionAuthentication, BasicAuthentication

# Create your views here.
class AuthenticationAPIView(APIView):
    # 局部的认证方式,支持多个认证方法
    authentication_classes = [SessionAuthentication]
    def get(self,request):
        print(request.user)
        # AnonymousUser 就是在request.user无法识别当前访问的客户端时的游客用户对象
        return Response("ok")

认证失败会有两种可能的返回值,这个需要我们配合权限组件来使用:

  • 401 Unauthorized 未认证

  • 403 Permission Denied 权限被禁止

自定义认证,component/authentication.py,代码:

# --- coding: utf-8 --
# @Author: lichaoming
# @Date  : 2024/12/05
from rest_framework.authentication import BaseAuthentication
from django.contrib.auth import get_user_model  # 自动识别当前django系统中的系统用户模型

class CustomBaseAuthentication(BaseAuthentication):
    """
    自定义认证方式
    """
    def authenticate(self, request):
        """核心认证方法"""
        user = request.query_params.get('user')
        pwd = request.query_params.get('pwd')
        if user != "root" or pwd != "houmen":
            return None
        # get_user_model获取当前系统中用户表对应的用户模型类
        user = get_user_model().objects.filter(is_superuser=1, is_active=1).first()
        return (user, None)  # 按照固定的返回格式填写 (用户模型对象, None)

 

 

 

视图调用自定义认证,视图代码:

from rest_framework.authentication import SessionAuthentication
from rest_framework.views import APIView
from rest_framework.response import Response
from .authentication import CustomBaseAuthentication
class AuthenticationAPIView(APIView):
    # 局部的认证方式,支持多个认证方法
    authentication_classes = [CustomBaseAuthentication]
    def get(self, request):
        print(request.user)
        # AnonymousUser 就是在request.user无法识别当前访问的客户端时的游客用户对象
        return Response("ok")

 

当然也可以注释掉上面视图中的配置,改成全局配置。settings.py,代码:

"""drf配置信息必须全部写在REST_FRAMEWORK配置项中"""
REST_FRAMEWORK = {
    # 配置认证方式的选项【drf的认证是内部循环遍历每一个注册的认证类,一旦认证通过识别到用户身份,则不会继续循环】
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'drfdemo.authentication.CustomAuthentication',            # 自定义认证
        'rest_framework.authentication.SessionAuthentication',  # session认证
        'rest_framework.authentication.BasicAuthentication',      # 基本认证
    )
}

 

权限Permissions

权限控制可以限制用户对于视图的访问和对于具有模型对象的访问。

  • 在APIView视图的dispatch()方法中调用initial方法中先进行视图访问权限的判断

    self.check_permissions(request)

  • 在GenericAPIView通过get_object()获取具体模型对象时,会进行模型对象访问权限的判断

    self.check_object_permissions(self.request, obj)

使用

可以在配置文件restframework/settings.py中默认的全局设置了权限管理类,源码:

REST_FRAMEWORK = {
    ....
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny',  # AllowAny 表示允许任何用户访问站点视图
    ],
}

如果要在项目覆盖默认配置rest_framework/settings.py的设置,则可以在项目配置文件中,settings.py,代码:

"""drf的配置"""
# from rest_framework.permissions import AllowAny, IsAuthenticated, IsAdminUser, IsAuthenticatedOrReadOnly
REST_FRAMEWORK = {
    # 配置认证方式的选项[全局配置]
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication', # session认证
        'rest_framework.authentication.BasicAuthentication',   # basic认证[基于账号密码]
    ],
    # 配置权限的选项[全局配置]
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.AllowAny',
    ]
}

也可以在具体的视图类中通过类属性permission_classes来进行局部设置,如

from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated, AllowAny
from demo.serializers import StudentModelSerializer, Student
class PermissionAPIView(ModelViewSet):
    authentication_classes = [CustomAuthentication]
    permission_classes = [AllowAny]  # 针对封闭内部系统,登录页面时谁都可以访问。
    # permission_classes = [IsAuthenticated]
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

 

提供的权限

  • AllowAny 允许所有用户进行操作访问,默认权限

  • IsAuthenticated 仅通过登录认证的用户进行操作访问

  • IsAdminUser 仅允许管理员用户进行操作访问

  • IsAuthenticatedOrReadOnly 已经登陆认证的用户可以对数据进行增删改操作,没有登陆认证的游客只能查看数据。

打开浏览器的无痕模式:Ctrl+Shift+N

举例

视图代码:

 

from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated, AllowAny, IsAdminUser
from demo.serializers import StudentModelSerializer, Student
class PermissionAPIView(ModelViewSet):
    # authentication_classes = [CustomAuthentication]
    # permission_classes = [AllowAny]  # 针对封闭内部系统,登录页面时谁都可以访问。
    permission_classes = [IsAdminUser]  # 设置当前视图,只有是管理员可以访问操作。
    # permission_classes = [IsAuthenticatedOrReadOnly]  # 登录用户可以操作,而游客只能查看数据
    # permission_classes = [IsAuthenticated]
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

 

路由代码:

# --- coding: utf-8 --
# @Author: lichaoming
# @Date  : 2024/12/05
from django.urls import path, re_path
from . import views

urlpatterns = [
    path("auth",views.AuthenticationAPIView.as_view()),
    path("pess/",views.PermissionAPIView.as_view({"get":"list","post":"create"})),
    re_path("^pess/(?P<pk>\d+)/$", views.PermissionAPIView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
]

 

 

 

 

 

 

自定义权限

如需自定义权限,需继承rest_framework.permissions.BasePermission父类,并实现以下两个任何一个方法或全部

  • .has_permission(self, request, view)

    是否可以访问视图, view表示当前视图对象,request可以通过user属性获取当前用户

  • .has_object_permission(self, request, view, obj)

    是否可以访问模型对象, view表示当前视图, obj为模型数据对象,request可以通过user属性获取当前用户

例如:

在当前子应用下,创建一个权限文件permissions.py中声明自定义权限类:

 

# --- coding: utf-8 --
# @Author: lichaoming
# @Date  : 2024/12/06

from rest_framework.permissions import BasePermission


class VVIPPermission(BasePermission):
    """
    VVIP权限
    自定义权限,可用于全局配置,也可以用于局部配置
    """

    def has_permission(self, request, view):
        """
        视图权限
        返回结果未True则表示允许访问视图类
        request: 本次客户端提交的请求对象
        view: 本次客户端访问的视图类
        """
        # # 写在自己要实现认证的代码过程。
        identity = request.query_params.get("identity")
        # # 返回值为True,则表示通行
        return identity == "vvip"

    def has_object_permission(self, request, view, obj):
        """
        模型权限,写了视图权限(has_permission)方法,一般就不需要写这个了。
        返回结果未True则表示允许操作模型对象
        """
        from stuapi.models import Student
        if isinstance(obj, Student):
            # 限制只有小明才能操作Student模型
            identity = request.query_params.get("identity")
            return identity == "vvip"  # 如果身份不是vvip,返回值为False,不能操作
        else:
            # 操作其他模型,直接放行
            return True

 

局部配置自定义权限,视图代码:

from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated, AllowAny, IsAdminUser
from demo.serializers import StudentModelSerializer, Student
from .permissions import VVIPPermission


class PermissionAPIView(ModelViewSet):
    # authentication_classes = [CustomAuthentication]
    # permission_classes = [AllowAny]  # 针对封闭内部系统,登录页面时谁都可以访问。
    # permission_classes = [IsAdminUser]  # 设置当前视图,只有是管理员可以访问操作。
    # permission_classes = [IsAuthenticatedOrReadOnly]  # 登录用户可以操作,而游客只能查看数据
    # permission_classes = [IsAuthenticated]
    permission_classes = [VVIPPermission]
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

settings.py,全局配置,代码:

"""drf的配置"""
# from rest_framework.permissions import AllowAny, IsAuthenticated, IsAdminUser, IsAuthenticatedOrReadOnly
REST_FRAMEWORK = {
    # 配置认证方式的选项[全局配置]
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.SessionAuthentication', # session认证
        'rest_framework.authentication.BasicAuthentication',   # basic认证[基于账号密码]
    ],
    # 配置权限的选项[全局配置]
    'DEFAULT_PERMISSION_CLASSES': [
        # 'rest_framework.permissions.IsAuthenticated',  # 如果将来的站点时封闭内部系统,则设置IsAuthenticated
        # 'rest_framework.permissions.AllowAny',         # 如果将来的站点时开放外部系统,则设置AllowAny
        'component.permissions.VVIPPermission'
    ]
}

访问地址:http://127.0.0.1:8000/component/pess/?identity=vvip

访问地址:http://127.0.0.1:8000/component/pess/

 

认证主要的作用就是识别客户端的访问者的身份,但是不能拦截客户端的访问。

权限是基于认证来实现的,但是权限可以针对不同身份的用户,进行拦截用户对视图、模型的访问操作。

 

 

 

 

 

posted @ 2025-06-24 15:05  minger_lcm  阅读(11)  评论(0)    收藏  举报