其他分享
首页 > 其他分享> > DRF JWT 用户认证

DRF JWT 用户认证

作者:互联网

环境说明:

python: 3.8
django: 3.2
djangorestframework-jwt 1.11.0

项目大概说明:
基于Django中的系统用户表进行扩展,通过jwt进行用户权限认证。

目录结构:
image


认证相关 视图

from rest_framework import status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.viewsets import ViewSet
from .serializers import UserInfoModelSerializer


class LoginViewSet(ViewSet):
    # 设置这个视图不需要认证就可以访问
    authentication_classes = []
    # 设置这个视图不需要任何权限就可以访问
    permission_classes = []

    @action(methods=["POST"], detail=False)
    def get_token(self, requests):
        # 验证传递过来的用户名密码是否为空
        if requests.data.get("username") and requests.data.get("password"):
            # 通过序列化器进行序列化,对密码进行验证
            serializer = UserInfoModelSerializer(data=requests.data)
            # 判断序列化器验证是否成功
            serializer.is_valid()
            return Response(status=status.HTTP_200_OK, data=serializer.data)
        else:
            return Response({'code': 'errors'})

认证相关 序列化类

from rest_framework import serializers
from rest_framework_jwt.serializers import jwt_payload_handler
from rest_framework_jwt.utils import jwt_encode_handler
from system.models import Users


# 用户获取token的序列化器
class UserInfoModelSerializer(serializers.ModelSerializer):
    username = serializers.CharField()
    # write_only=True 反序列化的时候必须写入,但是序列化的时候不会显示
    password = serializers.CharField(write_only=True)

    # read_only=True 反序列化的时候不需要这个字段,但是返回的时候会显示
    token = serializers.CharField(read_only=True)

    class Meta:
        model = Users
        fields = ["id", "username", "password", "token"]

    def validate(self, attrs):
        # 对密码进行校验
        try:
            user = Users.objects.get(username=attrs.get("username"))
        except Users.DoesNotExist:
            raise serializers.ValidationError(detail="用户名密码错误", code="validate")
        # 通过系统默认表中的check_password来检查用户输入的明文密码和数据库中的密码是否是相同的
        if user.check_password(attrs.get("password")):
            payload = jwt_payload_handler(user)
            # 要将token字段返回给前端就必须要在fields里面加上token字段
            # 通过jwt_encode_handler生成token
            attrs["token"] = jwt_encode_handler(payload)
            return attrs
        else:
            raise serializers.ValidationError(detail="用户名密码错误", code="validate")

认证相关 视图

from rest_framework import status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.viewsets import ViewSet
from .serializers import UserInfoModelSerializer


class LoginViewSet(ViewSet):
    authentication_classes = []
    permission_classes = []

    @action(methods=["POST"], detail=False)
    def get_token(self, requests):
        # 验证传递过来的用户名密码是否为空
        if requests.data.get("username") and requests.data.get("password"):
            # 通过序列化器进行序列化
            serializer = UserInfoModelSerializer(data=requests.data)
            # 判断序列化器验证是否成功
            serializer.is_valid()
            return Response(status=status.HTTP_200_OK, data=serializer.data)
        else:
            return Response({'code': 'errors'})

认证相关 总路由

from django.urls import path, include
from apps import views
from apps.views import BookViewSet

from myauth.views import LoginViewSet

urlpatterns = [
    path('login/', LoginViewSet.as_view({"post": 'get_token'})),
    # path('book/', BookViewSet.as_view({'get': 'list', 'post': 'create'}))
    path('system/', include('system.urls')),
]

urlpatterns += router.urls

系统用户表 Model

扩展了系统用户表之后,需要在settings中更改认证用户模型的配置

book/settings.py
# Users为自定定义的系统用户模型名称
AUTH_USER_MODEL = 'system.Users'

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

STATUS_CHOICES = (
    (0, "禁用"),
    (1, "启用"),
)

# 继承AbstractUser,相当于在系统用户表的基础上进行扩展字段
class Users(AbstractUser):
    username = models.CharField(max_length=150, unique=True, db_index=True, verbose_name="用户账号", help_text="用户账号")
    email = models.EmailField(max_length=255, verbose_name="邮箱", null=True, blank=True, help_text="邮箱")
    mobile = models.CharField(max_length=255, verbose_name="电话", null=True, blank=True, help_text="电话")
    avatar = models.CharField(max_length=255, verbose_name="头像", null=True, blank=True, help_text="头像")
    name = models.CharField(max_length=40, verbose_name="姓名", help_text="姓名")
    GENDER_CHOICES = (
        (0, "未知"),
        (1, "男"),
        (2, "女"),
    )
    gender = models.IntegerField(
        choices=GENDER_CHOICES, default=0, verbose_name="性别", null=True, blank=True, help_text="性别"
    )
    USER_TYPE = (
        (0, "后台用户"),
        (1, "前台用户"),
    )
    user_type = models.IntegerField(
        choices=USER_TYPE, default=0, verbose_name="用户类型", null=True, blank=True, help_text="用户类型"
    )
    update_datetime = models.DateTimeField(auto_now=True, null=True, blank=True, help_text="修改时间", verbose_name="修改时间")
    create_datetime = models.DateTimeField(auto_now_add=True, null=True, blank=True, help_text="创建时间",
                                           verbose_name="创建时间")

    class Meta:
        db_table = "system_users"
        verbose_name = "用户表"
        verbose_name_plural = verbose_name
        ordering = ("-create_datetime",)

系统用户表 序列化器

from django.contrib.auth.hashers import make_password
from rest_framework import serializers
from .models import Users

# 用于获取用户信息的序列化器,不返回密码
class UserInfoSerializer(serializers.ModelSerializer):
    # 针对模型中含有选项的,通过`get_字段名称_display`可以返回具体的名称
    gender = serializers.CharField(source="get_gender_display", read_only=True)

    class Meta:
        model = Users
        fields = ('id', 'username', 'email', 'mobile', 'avatar', 'name', 'gender', 'user_type',)


# 用于创建用户使用的序列化器
class UserCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = Users
        fields = ('id', 'username', 'password', 'name', 'email', 'mobile', 'gender', 'user_type',)
        # 增加约束键,对需要部分进行约束,相当于添加了判断
        extra_kwargs = {
            'username': {
                'max_length': 20,
                'min_length': 5
            },
            'password': {
                'max_length': 20,
                'min_length': 8,
                'write_only': True
            },
        }

    # 对单个字段进行验证,使用django自带的方法make_password
    def validate_password(self, value):
        password = self.initial_data.get("password")
        if password:
            return make_password(value)
        return value

系统用户表 视图

from rest_framework.decorators import action
from rest_framework.viewsets import ModelViewSet
from .models import Users
from .serializers import UserInfoSerializer, UserCreateSerializer
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticated
from myauth.authentications import JWTAuthentication


class UserModelViewSet(ModelViewSet):
    queryset = Users.objects.all()
    # 使用我们自定义的验证方法
    authentication_classes = [JWTAuthentication]
    # 登录成功才能进行访问
    permission_classes = [IsAuthenticated]

    # 重写类方法,判断从视图请求过来的方法来选择序列化器,GET请求对应list_user,POST对应create_user
    def get_serializer_class(self):
        if self.action == "list_user":
            return UserInfoSerializer
        elif self.action == "create_user":
            return UserCreateSerializer

    @action(methods=['get'], detail=True)
    def list_user(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    @action(methods=['post'], detail=True)
    def create_user(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

系统用户表 路由

from django.urls import path, re_path
from rest_framework.routers import DefaultRouter, SimpleRouter
from .views import UserModelViewSet

urlpatterns = [
    # 通过不同的请求方式请求到不同的方法中去
    path('user/', UserModelViewSet.as_view({'get': 'list_user', 'post': 'create_user'})),
    re_path('user/(?P<pk>\d+)/$', UserModelViewSet.as_view({'get': 'list_user'})),
]

标签:get,JWT,rest,认证,framework,user,import,True,DRF
来源: https://www.cnblogs.com/shangcc205/p/16455511.html