34.django使用jwt


1.jwt

這里是打包的代碼地址jwt代碼包

json web token:用於用戶認證(前后端分離/微信小程序/app開發)
- 基於傳統的token認證
	用戶登錄,服務端給返回token,並將token(服務端不保存)
    以后用戶再來訪問時,需要攜帶token,服務端獲取token后,再去數據庫中獲取token
- jwt
	用戶登陸之后,服務端給用戶返回一個token(服務器不保存)
    以后用戶訪問,都需要帶着token,服務器獲取token后,通過算法進行token驗證

優勢:相較於傳統的token相比,他無需在服務端保存token

2.jwt實現過程

1.提交用戶名和密碼給服務端,如果登錄成功,使用jwt生成一個token值,並返回給用戶

注意:jwt生成的token是由三段字符串通過.連接起來的

第一段字符串:HEADER,內部包含算法token類型。
json轉化成字符串,然后做base64url加密(base64加密;+-\)
{
    "alg": "HS256",
    'type': "JWT"
}
第二段字符串:payload,自定義值:
json轉化成字符串,然后做base64url加密(base64加密;+-\)
{
    'id': "124124",
    'name':'chengge',
    'exp': '1423434132',# 超時時間
}
第三段字符串:
第一步:將第1,2不封密文拼接起來
第二步:對前兩部分密文進行hs256加密+加鹽
第三步:對hs256加密后的密文在做base64url加密

- 以后用戶來訪問時候,攜帶token,后端需要對token進行校驗
	- 獲取token
    - 第一步:對token進行切割
    - 第二步:把第二段進行base64解密,並獲取payload信息,檢測超市時間
 	- 第二步:把第一個段拼接再次執行hs256加密+加鹽
    
    密文 = base64解密
    如果密文相等表示token沒有被修改過

3.應用

pip install pyjwt
pyjwt.encode 生成token
pyjwt.decode token解密

4.擴展

pip install djagnrestframework-jwt
djagnrestframework-jwt 本質上是調用pyjwt實現的

版本一:

原理就是服務端保存tokne

class LoginView(APIView):
    '''用戶登錄'''
    def post(self, request, *args, **kwargs):
        username = request.data.get("username")
        passwork = request.data.get("password")
        user_obj = models.UserInfo.objects.filter(username=username, password=passwork).first()
        if not user_obj:
            return Response({"code": 1000, 'error': '用戶名或密碼錯誤'})
        random_string = str(uuid.uuid4())
        user_obj.token = random_string
        user_obj.save()
        return Response({"code":1001, 'data': '登陸成功'})


class OrderView(APIView):
    def get(self, request, *args, **kwargs):
        token = request.query_params.get("token")
        print(token)
        if not token:
            Response({"code": 1003, 'error': '未登錄失敗'})
        user_obj = models.UserInfo.objects.filter(token=token).exists()
        if not user_obj:
            Response({"code": 1003, 'error': '未登錄失敗'})
        return Response("訂單列表")

版本二:

通過jwt進行驗證,但是發現每個函數都要使用太麻煩了

class JwtLoginView(APIView):
    '''用戶登錄'''
    def post(self, request, *args, **kwargs):
        username = request.data.get("username")
        passwork = request.data.get("password")
        user_obj = models.UserInfo.objects.filter(username=username, password=passwork).exists()
        if not user_obj:
            return Response({"code": 1000, 'error': '用戶名或密碼錯誤'})


        import jwt
        import datetime
        salt = "fadsf$@%#%#%gsfdgsdgfd"
        headers = {
            "typ": "jwt_",
            "alg": "HS256",
        }
        payload = {
            "user_id": 1,
            "username": "alex",
            "exp": datetime.datetime.utcnow() + datetime.timedelta(minutes=1)
        }

        token = jwt.encode(payload=payload, key=salt, headers=headers).decode("utf-8")
        return Response({"code":1001, 'data': token})


class JwtOrderView(APIView):
    def get(self, request, *args, **kwargs):
        # 獲取token並驗證
        token = request.query_params.get("token")
        import jwt
        from jwt import exceptions
        result = None
        msg = None
        salt = "fadsf$@%#%#%gsfdgsdgfd"
        try:
            result = jwt.decode(token, salt, True)
        except exceptions.ExpiredSignatureError:
            msg = "token失效"

        except exceptions.DecodeError:
            msg = "token認證失敗"
        except exceptions.InvalidTokenError:
            msg = "非法token"

        if not result:
            return Response({"code": 1002, "msg": msg})

        return Response("訂單列表")

版本三:

使用restful的認證組件認證

class PrLoginView(APIView):
    authentication_classes = []

    def post(self, request, *args, **kwargs):
        username = request.data.get("username")
        passwork = request.data.get("password")
        user_obj = models.UserInfo.objects.filter(username=username, password=passwork).first()
        if not user_obj:
            return Response({"code": 1000, 'error': '用戶名或密碼錯誤'})
        payload = {
            "id": user_obj.pk,
            "name": user_obj.username,
        }
        token = get_token(payload, 5)
        return Response({"code": 1001, 'data': token})


class PrOrderView(APIView):

    # authentication_classes = [JwtQuertParamsAuthentication]

    def get(self, request, *args, **kwargs):

        return Response("訂單列表")
# get_token函數
import jwt
import datetime
from django.conf import settings
def get_token(payload, timeout):
    salt = settings.SECRET_KEY
    headers = {
        "typ": "jwt_",
        "alg": "HS256",
    }
    payload["exp"] = datetime.datetime.utcnow() + datetime.timedelta(minutes=timeout)
    token = jwt.encode(payload=payload, key=salt, headers=headers).decode("utf-8")
    return token

實現一個restframework的認證類,將它應用到視圖函數之中就可以了

import jwt
from jwt import exceptions
from rest_framework.authentication import BaseAuthentication
from django.conf import settings
from rest_framework.exceptions import AuthenticationFailed
class JwtQuertParamsAuthentication(BaseAuthentication):
    def authenticate(self, request):
        token = request.query_params.get("token")
        salt = settings.SECRET_KEY
        try:
            result = jwt.decode(token, salt, True)
        except exceptions.ExpiredSignatureError:
            msg = "token失效"
            raise AuthenticationFailed({"code": 1001, "msg": msg})
        except exceptions.DecodeError:
            msg = "token認證失敗"
            raise AuthenticationFailed({"code": 1002, "msg": msg})

        except exceptions.InvalidTokenError:
            msg = "非法token"
            raise AuthenticationFailed({"code": 1003, "msg": msg})

        return (result, token)

        # 三種操作
        # 1.拋出錯誤,后續不再執行
        # 2.return一個元組,(1,2)認證通過,在視圖中如果調用request.user 就是第一個值request.auth就是第二個
        # 3.None不做任何操作


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM