django rest framework jwt 的使用


簡單介紹一下jwt
Json Web Token(JWT)
JWT 是一個開放標准(RFC 7519),它定義了一種用於簡潔,自包含的用於通信雙方之間以 JSON 對象的形式安全傳遞信息的方法。JWT 可以使用 HMAC 算法或者是 RSA 的公鑰密鑰對進行簽名。它具備兩個特點:

簡潔(Compact)
可以通過URL, POST 參數或者在 HTTP header 發送,因為數據量小,傳輸速度快

自包含(Self-contained)
負載中包含了所有用戶所需要的信息,避免了多次查詢數據庫

詳情請查看這篇文章
https://www.jianshu.com/p/180a870a308a

或者:點我

JWT長什么樣?

JWT是由三段信息構成的,將這三段信息文本用.鏈接一起就構成了Jwt字符串。就像這樣:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ 

JWT的構成

第一部分我們稱它為頭部(header),第二部分我們稱其為載荷(payload, 類似於飛機上承載的物品),第三部分是簽證(signature).


header

jwt的頭部承載兩部分信息:

  • 聲明類型,這里是jwt
  • 聲明加密的算法 通常直接使用 HMAC SHA256

完整的頭部就像下面這樣的JSON:

{
  'typ': 'JWT',
  'alg': 'HS256'
}

 

然后將頭部進行base64加密(該加密是可以對稱解密的),構成了第一部分.

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

playload

載荷就是存放有效信息的地方這個名字像是特指飛機上承載的貨品,這些有效信息包含三個部分

  • 標准中注冊的聲明
  • 公共的聲明
  • 私有的聲明

標准中注冊的聲明 (建議但不強制使用) :

  • iss: jwt簽發者
  • sub: jwt所面向的用戶
  • aud: 接收jwt的一方
  • exp: jwt的過期時間,這個過期時間必須要大於簽發時間
  • nbf: 定義在什么時間之前,該jwt都是不可用的.
  • iat: jwt的簽發時間
  • jti: jwt的唯一身份標識,主要用來作為一次性token,從而回避重放攻擊。

公共的聲明
公共的聲明可以添加任何的信息,一般添加用戶的相關信息或其他業務需要的必要信息.但不建議添加敏感信息,因為該部分在客戶端可解密.

私有的聲明
私有聲明是提供者和消費者所共同定義的聲明,一般不建議存放敏感信息,因為base64是對稱解密的,意味着該部分信息可以歸類為明文信息。

定義一個payload:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

 

然后將其進行base64加密,得到Jwt的第二部分。

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

signature

jwt的第三部分是一個簽證信息,這個簽證信息由三部分組成

  • header (base64后的)
  • payload (base64后的)
  • secret

這個部分需要base64加密后的header和base64加密后的payload使用.連接組成的字符串,然后通過header中聲明的加密方式進行加鹽secret組合加密,然后就構成了jwt的第三部分。

// javascript
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);

var signature = HMACSHA256(encodedString, 'secret'); // TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

 

將這三部分用.連接成一個完整的字符串,構成了最終的jwt:

  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ 

注意:secret是保存在服務器端的,jwt的簽發生成也是在服務器端的,secret就是用來進行jwt的簽發和jwt的驗證,所以,它就是你服務端的私鑰,在任何場景都不應該流露出去。一旦客戶端得知這個secret, 那就意味着客戶端是可以自我簽發jwt了。

如何應用

一般是在請求頭里加入Authorization,並加上Bearer標注:

fetch('api/user/1', {
  headers: {
    'Authorization': 'Bearer ' + token
  }
})

 

服務端會驗證token,如果驗證通過就會返回相應的資源。整個流程就是這樣的:

 
jwt-diagram

總結

優點

  • 因為json的通用性,所以JWT是可以進行跨語言支持的,像JAVA,JavaScript,NodeJS,PHP等很多語言都可以使用。
  • 因為有了payload部分,所以JWT可以在自身存儲一些其他業務邏輯所必要的非敏感信息。
  • 便於傳輸,jwt的構成非常簡單,字節占用很小,所以它是非常便於傳輸的。
  • 它不需要在服務端保存會話信息, 所以它易於應用的擴展

安全相關

  • 不應該在jwt的payload部分存放敏感信息,因為該部分是客戶端可解密的部分。
  • 保護好secret私鑰,該私鑰非常重要。
  • 如果可以,請使用https協議
 

 

使用

---------------------

Django REST framework JWT 的使用

安裝

pip install djangorestframework-jwt
配置

SECRET_KEY = '8bu4e=em53a(p904(#^0)f0hx@gz)!8_(2h@jih@*&6dy-2*c*'  #用於jwt簽發和驗證,這個千萬不能泄漏,否則客戶端也可以隨意簽發jwt,有安全風險

REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.BasicAuthentication', ), } JWT_AUTH = { 'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1), }

注意:secret_key是保存在服務器端的,jwt的簽發生成也是在服務器端的secret_key就是用來進行jwt的簽發jwt的驗證,所以,它就是你服務端的私鑰,在任何場景都不應該流露出去。一旦客戶端得知這個secret, 那就意味着客戶端是可以自我簽發jwt了。

 

JWT_EXPIRATION_DELTA 指明token的有效期

url.py

from django.contrib import admin
from django.urls import path,include
from rest_framework_jwt.views import obtain_jwt_token, verify_jwt_token, refresh_jwt_token
from accounts.views import xd_obtain_jwt_token
from common.views import page_not_found

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login', obtain_jwt_token, name='login'),#使用默認自帶的
    path('login', xd_obtain_jwt_token, name='login'),#或者這是使用自定義的
]

 

自定義的時候的寫法

from rest_framework_jwt.views import JSONWebTokenAPIView
from rest_framework_jwt.utils import jwt_response_payload_handler
from rest_framework_jwt.serializers import JSONWebTokenSerializer

class XD_JSONWebTokenAPIView(JSONWebTokenAPIView):
    """
    Base API View that various JWT interactions inherit from.
   """
    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)

        if serializer.is_valid():
            user = serializer.object.get('user') or request.user
            token = serializer.object.get('token')
            response_data = jwt_response_payload_handler(token, user, request)
            response_data['is_first']=user.is_default_pwd
            response = Response(response_data)
            print(response,'這是response===',response_data,user,type(user))
            if api_settings.JWT_AUTH_COOKIE:
                print('是否進來了')
                expiration = (datetime.utcnow() +
                              api_settings.JWT_EXPIRATION_DELTA)
                response.set_cookie(api_settings.JWT_AUTH_COOKIE,
                                    token,
                                    expires=expiration,
                                    httponly=True)
            return response

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class ObtainJSONWebToken(XD_JSONWebTokenAPIView):
    """
    API View that receives a POST with a user's username and password.

    Returns a JSON Web Token that can be used for authenticated requests.
    """
    serializer_class = JSONWebTokenSerializer


xd_obtain_jwt_token = ObtainJSONWebToken.as_view()

 

JSONWebTokenSerializer做的工作:
1.

 

登陸數據用戶名密碼前段得到的返回值:

{
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6IjE4NzAxNTEzNDQwIiwiZXhwIjoxNTQ0ODQ1MjgzLCJwaG9uZSI6IjE4NzAxNTEzNDQwIn0.Gt7VUIFbW3wski9c53nw69IiIP-5l_0xKNpPimz2BJg",
    "is_first": true
}

 


免責聲明!

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



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