ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

DRF JWT 用户认证

2022-07-07 17:34:35  阅读:172  来源: 互联网

标签:get JWT rest 认证 framework user import True DRF


环境说明:

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有