python-jwt用戶認(rèn)證食用教學(xué)的實現(xiàn)方法
jwt
詳解Django之a(chǎn)uth模塊(用戶認(rèn)證)
jwt的作用
json web token,一般用于用戶認(rèn)證就是做用戶登錄的(前后端分離/微信小程序/app開發(fā))

基于傳統(tǒng)的token認(rèn)證
用戶登錄,服務(wù)端返回token,并將token保存在服務(wù)端,
以后用戶再來訪問時,需要攜帶token,服務(wù)端獲取token后,再去數(shù)據(jù)庫中獲取token進(jìn)行校驗
jwt
用戶登錄,服務(wù)端給用戶返回一個token(服務(wù)端不保存)
以后用戶再來訪問,需要攜帶token,服務(wù)端獲取token后,再做token的校驗----進(jìn)行算法校驗
優(yōu)勢:相較于傳統(tǒng)的token相比,它無需在服務(wù)端保存token
jwt的實現(xiàn)原理
第一步,用戶提交用戶名和密碼給服務(wù)器,如果登錄成功,使用jwt創(chuàng)建一個token,并給用戶返回.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
注意:jwt生成的token是由三段字符串組成,并且用.連接起來的
第一段字符串,HEADER,內(nèi)部包含了算法/token類型,
json轉(zhuǎn)換成字符串,然后做一個base64url加密(base64加密;+_),加密再加替換
{
"alg": "HS256",
"typ": "JWT"
}
第二段字符串,PAYLOAD,自定義的值
讓json轉(zhuǎn)換成字符串,然后做一個base64url加密(base64加密;+_),加密再加替換
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022 # 前兩個隨便寫,最后一個是超時時間
}
第三段字符串:他會將第一段加密之后的值,和第二段加密之后的值通過.拼接起來
第一步:第1,2部分的密文拼接起來
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
第二步:對前兩部分密文進(jìn)行HS256加密 + 加鹽
第三步:對HS256加密后的密文再做base64url加密
以后用戶再來訪問的時候,需要攜帶token,后端需要對token進(jìn)行校驗
獲取token
第一步: 對token進(jìn)行切割,通過點切割成三部分
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
第二步: 對第二段進(jìn)行 base64url 解密,并獲取payload信息,檢測token是否超時了?
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022 # 前兩個隨便寫,最后一個是超時時間
}
第三步 :把第1,2段拼接,再次執(zhí)行HS256加密
第一步:第1,2部分的密文拼接起來
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
第二步:對前兩部分密文進(jìn)行HS256加密 + 加鹽
密文 = base64解密(SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c)
如果密文相等,表示token未被修改過(認(rèn)證通過)
jwt的引用
pip install pyjwt pyjwt.encode 生成token pyjwt.decode token解密
原理性的東西


基于jwt和drf實現(xiàn)用戶認(rèn)證
1.路由
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django.conf.urls import url, include
from api import views
urlpatterns = [ url('^login/$', views.LoginView.as_view()), url('^order/$', views.OrderView.as_view()),]
views
from rest_framework.views import APIView
from rest_framework.response import Response
from utils.jwt_auth import create_token
from extensions.auth import JwtQueryParamAuthentication, JwtAuthorizationAuthentication
class LoginView(APIView):
def post(self, request, *args, **kwargs):
""" 用戶登錄 """
user = request.POST.get('username')
pwd = request.POST.get('password')
# 檢測用戶和密碼是否正確,此處可以在數(shù)據(jù)進(jìn)行校驗。
if user == 'wupeiqi' and pwd == '123':
# 用戶名和密碼正確,給用戶生成token并返回
token = create_token({'username': 'wupeiqi'})
return Response({'status': True, 'token': token})
return Response({'status': False, 'error': '用戶名或密碼錯誤'})
class OrderView(APIView):
# 通過url傳遞token
authentication_classes = [JwtQueryParamAuthentication, ]
# 通過Authorization請求頭傳遞token
# authentication_classes = [JwtAuthorizationAuthentication, ]
def get(self, request, *args, **kwargs):
print(request.user, request.auth)
return Response({'data': '訂單列表'})
def post(self, request, *args, **kwargs):
print(request.user, request.auth)
return Response({'data': '添加訂單'})
def put(self, request, *args, **kwargs):
print(request.user, request.auth)
return Response({'data': '修改訂單'})
def delete(self, request, *args, **kwargs):
print(request.user, request.auth)
return Response({'data': '刪除訂單'})
settings
SECRET_KEY = '-(e4!74gqo8q@v-y#0cz9e7aeux4qx-pl1xw#05co4avr8r+r0'
REST_FRAMEWORK = {
"DEFAULT_VERSIONING_CLASS": 'rest_framework.versioning.URLPathVersioning',
"ALLOWED_VERSIONS": ['v1', "v2"] #兩個認(rèn)證版本
}
extensions.auth
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.authentication import BaseAuthentication
from rest_framework import exceptions
from utils.jwt_auth import parse_payload
class JwtQueryParamAuthentication(BaseAuthentication):
"""
用戶需要在url中通過參數(shù)進(jìn)行傳輸token,例如:
http://www.pythonav.com?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NzM1NTU1NzksInVzZXJuYW1lIjoid3VwZWlxaSIsInVzZXJfaWQiOjF9.xj-7qSts6Yg5Ui55-aUOHJS4KSaeLq5weXMui2IIEJU
"""
def authenticate(self, request):
token = request.query_params.get('token')
payload = parse_payload(token)
if not payload['status']:
raise exceptions.AuthenticationFailed(payload)
# 如果想要request.user等于用戶對象,此處可以根據(jù)payload去數(shù)據(jù)庫中獲取用戶對象。
return (payload, token)
class JwtAuthorizationAuthentication(BaseAuthentication):
"""
用戶需要通過請求頭的方式來進(jìn)行傳輸token,例如:
Authorization:jwt eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NzM1NTU1NzksInVzZXJuYW1lIjoid3VwZWlxaSIsInVzZXJfaWQiOjF9.xj-7qSts6Yg5Ui55-aUOHJS4KSaeLq5weXMui2IIEJU
"""
def authenticate(self, request):
# 非登錄頁面需要校驗token
authorization = request.META.get('HTTP_AUTHORIZATION', '')
auth = authorization.split()
if not auth:
raise exceptions.AuthenticationFailed({'error': '未獲取到Authorization請求頭', 'status': False})
if auth[0].lower() != 'jwt':
raise exceptions.AuthenticationFailed({'error': 'Authorization請求頭中認(rèn)證方式錯誤', 'status': False})
if len(auth) == 1:
raise exceptions.AuthenticationFailed({'error': "非法Authorization請求頭", 'status': False})
elif len(auth) > 2:
raise exceptions.AuthenticationFailed({'error': "非法Authorization請求頭", 'status': False})
token = auth[1]
result = parse_payload(token)
if not result['status']:
raise exceptions.AuthenticationFailed(result)
# 如果想要request.user等于用戶對象,此處可以根據(jù)payload去數(shù)據(jù)庫中獲取用戶對象。
return (result, token)
utils.jwt_auth
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import jwt
import datetime
from jwt import exceptions
JWT_SALT = 'iv%x6xo7l7_u9bf_u!9#g#m*)*=ej@bek5)(@u3kh*72+unjv='
def create_token(payload, timeout=20):
"""
:param payload: 例如:{'user_id':1,'username':'wupeiqi'}用戶信息
:param timeout: token的過期時間,默認(rèn)20分鐘
:return:
"""
headers = {
'typ': 'jwt',
'alg': 'HS256'
}
payload['exp'] = datetime.datetime.utcnow() + datetime.timedelta(minutes=timeout)
result = jwt.encode(payload=payload, key=JWT_SALT, algorithm="HS256", headers=headers).decode('utf-8')
return result
def parse_payload(token):
"""
對token進(jìn)行和發(fā)行校驗并獲取payload
:param token:
:return:
"""
result = {'status': False, 'data': None, 'error': None}
try:
verified_payload = jwt.decode(token, JWT_SALT, True)
result['status'] = True
result['data'] = verified_payload
except exceptions.ExpiredSignatureError:
result['error'] = 'token已失效'
except jwt.DecodeError:
result['error'] = 'token認(rèn)證失敗'
except jwt.InvalidTokenError:
result['error'] = '非法的token'
return result
擴(kuò)展
pip3 install djangorestframework-jwt 和上面的類似不建議使用,就是加了一些配置文件,只能在drf中用,太局限l
djangorestframework-jwt 本質(zhì)是調(diào)用pyjwt實現(xiàn)的
使用場景兩端開發(fā),app,小程序開發(fā)!
到此這篇關(guān)于python-jwt用戶認(rèn)證食用教學(xué)的文章就介紹到這了,更多相關(guān)python-jwt認(rèn)證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python利用openpyxl拆分多個工作表的工作簿的方法
這篇文章主要介紹了python利用openpyxl拆分多個工作表的工作簿的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
python3中_from...import...與import?...之間的區(qū)別詳解(包/模塊)
Python編碼第一步是導(dǎo)入模塊,有時候用import?***有時候用from...import,下面這篇文章主要給大家介紹了關(guān)于python3中_from...import...與import?...之間區(qū)別的相關(guān)資料,需要的朋友可以參考下2022-08-08
Django開發(fā)中使用Ueditor上傳圖片遇到的坑及解決
在Django開發(fā)中使用Ueditor上傳圖片時,可能會遇到后端配置不正確的問題,建議在實例化Ueditor后加上serverUrl,這可以在Chrome的F12工具中查看請求的后端配置項,此外,如果需要修改上傳路徑,可以在配置文件中更改路徑,并調(diào)整view.py中的代碼來管理上傳文件2024-09-09

