drf_jwt

JWT:

1、組成: header.payload.signature 頭.載荷.簽名 2、示例: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6Im93ZW4iLCJleHAiOjE1NTgzMDM1NDR9.4j5QypLwufjpqoScwUB9LYiuhYcTw1y4dPrvnv7DUyo 3:介紹: header:通常存放如何處理token的方式:加密的算法、是否有簽名等 payload:數據的主體部分:用戶信息、發行者、過時時間等 signature:簽名:將header、payload再結合密碼鹽總體處理一下

 

工做原理:

1) jwt = base64(頭部).base64(載荷).hash256(base64(頭部).base(載荷).密鑰)
2) base64是可逆的算法、hash256是不可逆的算法
3) 密鑰是固定的字符串,保存在服務器

 

官網:https://github.com/jpadilla/django-rest-framework-jwt

安裝:pip install djangorestframework-jwt

 

使用:通常是搭配xadmin去實現後臺管理python

 

得到token:git

在user/url.py裏:


from django.urls import path
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
    path('login/', obtain_jwt_token),
]


利用postman測試發射post請求:


接口:http://127.0.0.1:8000/user/login/

數據:
{
    "username":"admin",
    "password":"admin"
}
可能存在一些問題:

Unable to log in with provided credentials


緣由是這種算法內部是須要使用auth_user表去獲取用戶的帳號和密碼數據的,而咱們沒有建立相關的數據,所以須要建立一些數據:

 python manage.py createsuperuser

再次嘗試:獲得token值:
 "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFkbWluIiwiZXh
wIjoxNTY5MjAyODc1LCJlbWFpbCI6IjEzMDYzNDczMzgwQDE2My5jb20ifQ.JgbSItmx0sa4JHuA5I4J58gcoeCgTLKZaPj0T-f5OwI"


 

雖然說拿到了後端生成的token值,可怎麼讓其真正的實現認證功能呢:github

 

 在settinngs.py裏配置jwt的相關數據

import datetime
JWT_AUTH = {
    # 過時時間
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
    # 自定義認證類
    'JWT_RESPONSE_PAYLOAD_HANDLER': 'user.utils.jwt_response_payload_handler',  
}

 

 序列化組件 user/serializers.py

from rest_framework import serializers
from .models import User
class UserModelSerializer(serializers.ModelSerializer):
    """輪播圖序列化器"""
    class Meta:
        model = User
        fields = ["username", "mobile"]


須要注意的是:User這張表繼承的是  from django.contrib.auth.models import AbstractUser  ,由於jwt內部走的是auth_user這張表。    同時還須要在配置裏將 AUTH_USER_MODEL = 'app的名字.User' 添加上,表示重寫了auth的認證表
同時:由於重寫了auth表,須要刪除一些遷移記錄文件:django/contrib/admin/migrations
django/contrib/auth/migrations
xadmin/migrations  若是使用xadmin做爲後臺管理使用
reversion/migrations 同上
user/migrations

 

在user/models.py下:


from django.db import models

# Create your models here.
from django.contrib.auth.models import AbstractUser

class  User(AbstractUser):
    mobile = models.CharField(max_length=32,default=0)
    age = models.IntegerField(default=0)

 

自定義response的返回結果: user/utils.py

from .serializers import UserModelSerializers
def jwt_response_payload_handler(token, user=None, request=None):
    return {
        'token': token,
        # 拿到的是一個序列化後的對象,多個對象加上many=True
        'user': UserModelSerializer(user).data
    }
    # restful 規範
    # return {
    #     'status': 0,
    #     'msg': 'OK',
    #     'data': {
    #         'token': token,
    #         'username': user.username
    #     }
    # }

 

上述操做完成了jwt的自定義返回值,如今須要實現的是jwt全局認證,基於drf的認證組件實現算法

import jwt
from rest_framework.exceptions import AuthenticationFailed
from rest_framework_jwt.authentication import jwt_decode_handler
from rest_framework_jwt.authentication import get_authorization_header
from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication


class JSONWebTokenAuthentication(BaseJSONWebTokenAuthentication):
    def authenticate(self, request):
        # 下面的 token獲取,能夠直接 request.META.get()去獲取
        token = get_authorization_header(request)
        # 能夠在此處 對請求頭的字段作出一些限制,實現反扒
        if not token:
            raise AuthenticationFailed('Authorization字段是必須的')

        try:
            payload = jwt_decode_handler(token)
        except jwt.ExpiredSignature:
            raise AuthenticationFailed('簽名過時')
        except jwt.DecodeError:
            raise AuthenticationFailed('錯誤的解碼簽名')
        except jwt.InvalidTokenError:
            raise AuthenticationFailed('非法用戶')

        user = self.authenticate_credentials(payload)

        return (user, token)

 

固然了,須要在settings.py裏完成相關配置:全局啓用django

EST_FRAMEWORK = {
    # 認證模塊
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'user.authentications.JSONWebTokenAuthentication',
    ),
}
須要知道,drf_jwt是基於drf框架實現的

 

局部啓用禁用:任何一個cbv類首行


# 局部禁用
authentication_classes = []

# 局部啓用
from user.authentications import JSONWebTokenAuthentication
authentication_classes = [JSONWebTokenAuthentication]

 

上述操做時針對於用戶密碼而言的,若是是多方式登錄如何利用jwt實現呢?後端

from django.contrib.auth.backends import ModelBackend
from .models import User
import re
class JWTModelBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        """
        :param request:
        :param username: 前臺傳入的用戶名,能夠是多方式下的數據
        :param password: 前臺傳入的密碼
        :param kwargs:
        :return:
        """
        try:
            if re.match(r'^1[3-9]\d{9}$', username):
                user = User.objects.get(mobile=username)
            elif re.match(r'.*@.*', username):
                user = User.objects.get(email=username)
            else:
                user = User.objects.get(username=username)
        except User.DoesNotExist:
            return None  # 認證失敗就返回None便可,jwt就沒法刪除token
        # 用戶存在,密碼校驗經過,是活着的用戶 is_active字段爲1
        if user and user.check_password(password) and self.user_can_authenticate(user):
            return user  # 認證經過返回用戶,交給jwt生成token

 

配置多方式登錄:   settings.py

AUTHENTICATION_BACKENDS = ['user.utils.JWTModelBackend']

 

手動簽發jwt: 擁有原生登錄基於model類user對象簽發 jwtapi

from rest_framework_jwt.settings import api_settings服務器

jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLERrestful

payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)app

# 瞭解,原生視圖# 原生APIView能夠實現手動簽發 jwtclass LoginAPIView(APIView): def post(self): # 完成手動簽發 pass

本站公眾號
   歡迎關注本站公眾號,獲取更多信息