djangorestframework-jwt 用戶token認證

1. 項目app01
models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.

class UserProfile(AbstractUser):
    """
    用戶
    """
    name = models.CharField(max_length=30, null=True, blank=True, verbose_name="姓名")
    birthday = models.DateField(null=True, blank=True, verbose_name="出生年月")
    gender = models.CharField(max_length=6, choices=(("male", u"男"), ("female", "女")), default="female",
                              verbose_name="性別")
    mobile = models.CharField(null=True, blank=True, max_length=11, verbose_name="電話")
    email = models.EmailField(max_length=100, null=True, blank=True, verbose_name="郵箱")

    class Meta:
        verbose_name = "用戶"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.username
        
serializers.py 序列化文件
# -*- coding: utf-8 -*-
__author__ = 'hyh'

from django.contrib.auth import get_user_model
from rest_framework import serializers
User = get_user_model()

class UserRegSerializer(serializers.ModelSerializer):
    # code = serializers.CharField(required=True, write_only=True, max_length=4, min_length=4,label="驗證碼",
    #                              error_messages={
    #                                  "blank": "請輸入驗證碼",
    #                                  "required": "請輸入驗證碼",
    #                                  "max_length": "驗證碼格式錯誤",
    #                                  "min_length": "驗證碼格式錯誤"
    #                              },
    #                              help_text="驗證碼")
    username = serializers.CharField(label="用戶名", help_text="用戶名", required=True, allow_blank=False,
                                     validators=[UniqueValidator(queryset=User.objects.all(), message="用戶已經存在")])

    password = serializers.CharField(
        style={'input_type': 'password'},help_text="密碼", label="密碼", write_only=True,
    )

    def create(self, validated_data):
        user = super(UserRegSerializer, self).create(validated_data=validated_data)
        user.set_password(validated_data["password"])
        user.save()
        return user

    # def validate_code(self, code):
    #     # try:
    #     #     verify_records = VerifyCode.objects.get(mobile=self.initial_data["username"], code=code)
    #     # except VerifyCode.DoesNotExist as e:
    #     #     pass
    #     # except VerifyCode.MultipleObjectsReturned as e:
    #     #     pass
    #     verify_records = VerifyCode.objects.filter(mobile=self.initial_data["username"]).order_by("-add_time")
    #     if verify_records:
    #         last_record = verify_records[0]
    #
    #         five_mintes_ago = datetime.now() - timedelta(hours=0, minutes=5, seconds=0)
    #         if five_mintes_ago > last_record.add_time:
    #             raise serializers.ValidationError("驗證碼過時")
    #
    #         if last_record.code != code:
    #             raise serializers.ValidationError("驗證碼錯誤")
    #
    #     else:
    #         raise serializers.ValidationError("驗證碼錯誤")

    def validate(self, attrs):
        attrs["mobile"] = attrs["username"]
        #del attrs["code"]
        return attrs

    class Meta:
        model = User
        fields = "__all__"


2.安裝djangorestframework-jwt
pip install djangorestframework-jwt

配置settings文件
添加以下配置
import datetime
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        #'rest_framework_jwt.authentication.JSONWebTokenAuthentication', # 全局設置
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    ),
}
JWT_AUTH = {
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),
    'JWT_AUTH_HEADER_PREFIX': 'JWT',
}
AUTH_USER_MODEL = 'app01.UserProfile' # 自定義用戶表
#AUTHENTICATION_BACKENDS = (
#     # 將backends添加進setting
#     'app01.views.CustomBackend',
#) 自定義認證不可用
# redis緩存
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "PASSWORD": "123456",
        }
    }
}


view.py
from django.shortcuts import render
from django.contrib.auth.backends import ModelBackend
from rest_framework import viewsets
from rest_framework import mixins
from rest_framework import authentication
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework_jwt.serializers import jwt_encode_handler, jwt_payload_handler
from django.contrib.auth import get_user_model
from .serializers import UserRegSerializer
from django.db.models import Q
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import UserProfile
from django.http import JsonResponse
from rest_framework.permissions import IsAuthenticated
from rest_framework import permissions
from app01.utils.permissions import IsOwnerOrReadOnly
from rest_framework_extensions.cache.mixins import CacheResponseMixin #pip3 install drf-extensions # 使用緩存ListCacheResponseMixin,RetrieveCacheResponseMixin
# Create your views here.

User = get_user_model()


#class CustomBackend(ModelBackend):
#    """
#    自定義用戶驗證
#    """
#    def authenticate(self, username=None, password=None, **kwargs):
#        try:
#            user = UserProfile.objects.get(Q(username=username)|Q(mobile=username))
#            if user.check_password(password):
#                return user
#        except Exception as e:
#            return None


class UserViewset(CacheResponseMixin,mixins.CreateModelMixin, mixins.UpdateModelMixin, mixins.RetrieveModelMixin,mixins.ListModelMixin, viewsets.GenericViewSet):
    serializer_class = UserRegSerializer
    queryset = UserProfile.objects.all()
    #permission_classes = (IsAuthenticated, IsOwnerOrReadOnly) # 權限和認證必須同時使用,不然認證不生效
    authentication_classes = (JSONWebTokenAuthentication,authentication.SessionAuthentication)

    def get_serializer_class(self):
        if self.action == "retrieve":
            return UserRegSerializer
        elif self.action == "create":
            return UserRegSerializer

        return UserProfileSerializer

    # permission_classes = (permissions.IsAuthenticated, )
    def get_permissions(self):
        if self.action == "retrieve":
            return [permissions.IsAuthenticated()]
        elif self.action == "list":
            return [permissions.IsAuthenticated()] #list也須要認證
        elif self.action == "create":
            return []

        return []

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = self.perform_create(serializer)

        re_dict = serializer.data
        payload = jwt_payload_handler(user)
        re_dict["token"] = jwt_encode_handler(payload)
        re_dict["name"] = user.name if user.name else user.username

        headers = self.get_success_headers(serializer.data)
        return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers)

    def get_object(self):
        return self.request.user

    def perform_create(self, serializer):
        return serializer.save()


class Index(CacheResponseMixin,APIView):
    permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
    authentication_classes = (JSONWebTokenAuthentication,)
    def get(self,request):
        return JsonResponse({"index":"ok"})
            
 3.urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import url,include
from rest_framework.routers import SimpleRouter,DefaultRouter
from rest_framework.documentation import include_docs_urls
from app01.views import UserViewset,Index
from rest_framework_jwt.views import obtain_jwt_token
router = SimpleRouter()
router.register('user',UserViewset,base_name='useruinfo')
urlpatterns = [
    path('admin/', admin.site.urls),
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    url(r'docs/', include_docs_urls(title="user信息")),
    url(r'^login/',obtain_jwt_token),
    url(r'^index/',Index.as_view()),
]

urlpatterns += router.urls
        
        
 4. 在app01下建立utils目錄,存放permissions.py文件
 permissions.py文件內容
 # -*- coding: utf-8 -*-
__author__ = 'hyh'
from rest_framework import permissions


class IsOwnerOrReadOnly(permissions.BasePermission):
    """
    Object-level permission to only allow owners of an object to edit it.
    Assumes the model instance has an `owner` attribute.
    """

    def has_object_permission(self, request, view, obj):
        # Read permissions are allowed to any request,
        # so we'll always allow GET, HEAD or OPTIONS requests.
        if request.method in permissions.SAFE_METHODS:
            return True

        # Instance must have an attribute named `owner`.
        return obj.user == request.user
 4.測試
 獲取token

image.png


複製token
python

image.png


返回結果成功redis

相關文章
相關標籤/搜索