一、JWT認證介紹
1 不再使用Session認證機制,而使用Json Web Token(本質就是token)認證機制,用戶登錄認證 2 用戶只要登錄了,返回用戶一個token串(隨機字符串),每次用戶發請求,需要攜帶這個串過來,驗證通過,我們認為用戶登錄了 3 JWT的構成(字符串) -三部分(每一部分中間通過.分割):header payload signature -header:聲明類型,這里是jwt,聲明加密算法,頭里加入公司信息...,用base64轉碼 { 'typ': 'JWT', 'alg': 'HS256' #用md5也行 } -payload:荷載(有用),當前用戶的信息(用戶名,id,這個token的過期時間,手機號),用base64轉碼 { "sub": "1234567898", "name": "egon", "admin": true, "userid":1, 'mobile':123444444 } -signature:簽名 -把前面兩部分的內容通過加密算法+密鑰加密后得到的一個字符串 -jwt總的構成樣子: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ 4 JWT認證原理 -用戶攜帶用戶名,密碼登錄我的系統,校驗通過,生成一個token(三部分),返回給用戶---》登錄功能完成 -訪問需要登錄的接口(用戶中心),必須攜帶token過來,后端拿到token后,把header和payload截出來,再通過一樣的加密方式和密碼得到一個signature,
和該token的signature比較,如果一樣,表示是正常的token,就可以繼續往后訪問
二、jwt基本使用(使用內置jwt)
安裝
1 drf中使用jwt,借助第三方https://github.com/jpadilla/django-rest-framework-jwt
2 安裝 pip3 install djangorestframework-jwt
快速使用
3 快速使用(默認使用auth的user表) (1) 在默認auth的user表中創建一個用戶 (2) 在路由中配置 from rest_framework_jwt.views import obtain_jwt_token path('login/', obtain_jwt_token), (3) 用postman向這個地址發送post請求,攜帶用戶名,密碼,登陸成功就會返回token (4)obtain_jwt_token本質也是一個視圖類,繼承了APIView -通過前端傳入的用戶名密碼,校驗用戶,如果校驗通過,生成token,返回 -如果校驗失敗,返回錯誤信息 訪問地址:http://127.0.0.1:8000/homework/login/
用戶登錄以后才能訪問某個接口
4 用戶登錄以后才能訪問某個接口 -jwt模塊內置了認證類,拿過來局部配置就可以 -class OrderView(APIView): # 只配它不行,不管是否登錄,都能范圍,需要搭配一個內置權限類 authentication_classes = [JSONWebTokenAuthentication, ] permission_classes = [IsAuthenticated,] def get(self, request): print(request.user.username) return Response('訂單的數據') 訪問地址: http://127.0.0.1:8000/homework/order/ 注意:訪問的時候需要在header內攜帶jwt
用戶未登錄,可以訪問
5 用戶未登錄,可以訪問 -class OrderView(APIView): # 只配它不行,不管是否登錄,都能范圍,需要搭配一個內置權限類 authentication_classes = [JSONWebTokenAuthentication, ] def get(self, request): print(request.user.username) return Response('訂單的數據') 訪問地址: http://127.0.0.1:8000/homework/order/
注意事項
6 如果用戶攜帶了token,並且配置了JSONWebTokenAuthentication,從request.user就能拿到當前登錄用戶,如果沒有攜帶,當前登錄用戶就是匿名用戶 7 前端要發送請求,攜帶jwt,格式必須如下 -把token放到請求頭header中,key為:Authorization -value必須為:jwt eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjo1LCJ1c2VybmFtZSI6ImVnb24xIiwiZXhwIjoxNjA1MjQxMDQzLCJlbWFpbCI6IiJ9.7Y3PQM0imuSBc8CUe_h-Oj-2stdyzXb_U-TEw-F82WE
三、
1 控制登錄接口返回的數據格式如下 { code:100 msg:登錄成功 token:asdfasfd username:egon } 2 寫一個函數utils.py from homework.serializer import UserReadOnlyModelSerializer def jwt_response_payload_handler(token, user=None, request=None): return {'code': 100, 'msg': '登錄成功', 'token': token, 'user': UserReadOnlyModelSerializer(instance=user).data } 3 在setting.py中配置 import datetime JWT_AUTH = { 'JWT_RESPONSE_PAYLOAD_HANDLER': 'app01.utils.jwt_response_payload_handler', }
四、
1 自己實現基於jwt的認證類,通過認證,才能繼續訪問,通不過認證就返回錯誤
2 自己寫個類auth.py class JwtAuthentication(BaseJSONWebTokenAuthentication): def authenticate(self, request): # 認證邏輯() # token信息可以放在請求頭中,請求地址中 # key值可以隨意叫 # token=request.GET.get('token') token=request.META.get('HTTP_Authorization'.upper()) # 校驗token是否合法 try: payload = jwt_decode_handler(token) except jwt.ExpiredSignature: raise AuthenticationFailed('過期了') except jwt.DecodeError: raise AuthenticationFailed('解碼錯誤') except jwt.InvalidTokenError: raise AuthenticationFailed('不合法的token') user=self.authenticate_credentials(payload) return (user, token)
3 在視圖類中配置 authentication_classes = [JwtAuthentication, ] # 視圖views.py全代碼: from app01.auth import JwtAuthentication class OrderView(APIView): # 登錄以后才能訪問 authentication_classes = [JwtAuthentication, ] def get(self, request): print(request.user.username) return Response('訂單的數據')