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不做任何操作