JWT驗證

JWT(Json Web Token):是目前最流行的跨域身份驗證解決方案。
此前咱們使用的身份驗證方式都是基於Session:
clipboard.png
這種方式並無什麼不妥,但其實這裏有三個缺點:html

  1. Session通常存儲在redis中,而redis數據保存在內存中,隨着用戶的增多,內存消耗太大。
  2. 擴展性很差,用戶每次驗證都須要請求session服務器,增大了負載均衡能力,應用擴展受限。
  3. 由於是基於cookie來進行用戶識別的, cookie若是被截獲,用戶就會很容易受到跨站請求僞造的攻擊。

因此,咱們須要一種既能實現相同要求而且還要比session存儲更有效的身份驗證方式。前端

clipboard.png
JWT經過一種加密的方式,將加密後的數據保存返回給用戶本地進行保存,咱們稱爲token數據。其數據由三部分組成:redis

一、header聲明類型和加密的算法:算法

{
  'typ': 'JWT',    #固定值
  'alg': 'HS256'    #加密算法
}

二、payload負載
這是有效信息的存放地方,其分爲三部分:標準中註冊的聲明、公共聲明、私有聲明(用戶信息)
標準中的註冊聲明(有須要在使用,不強制使用):
iss: jwt簽發者
sub: jwt所面向的用戶
aud: 接收jwt的一方
exp: jwt的過時時間,這個過時時間必需要大於簽發時間
nbf: 定義在什麼時間以前,該jwt都是不可用的.
iat: jwt的簽發時間
jti: jwt的惟一身份標識,主要用來做爲一次性token,從而回避重放攻擊。
公共聲明:公共的聲明能夠添加任何的信息,通常添加用戶的相關信息或其餘業務須要的必要信息.
私有聲明:django

{
  "name": "jim",
  "id": "111111",
  "admin": true
}

三、signature簽名
須要base64加密後的header和base64加密後的payload使用.鏈接組成的字符串,而後經過header中聲明的加密方式進行加鹽secret組合加密,而後就構成了jwt的第三部分。因爲base64是對稱加密算法,因此能夠輕鬆解密:所以咱們在負載部分不要將私密信息放置在裏面,只須要把能驗證惟一的標識信息添加就能夠了。
有關base64,請參考:https://www.liaoxuefeng.com/w...
因爲目前在學習DRF,因此我介紹一下怎樣在DRF項目中使用JWT進行身份驗證:
安裝djangorestframework-jwt:後端

pip install djangorestframework-jwt

添加jwt認證類:api

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication',
    ),
}

添加jwt路由用於生成token:跨域

from rest_framework_jwt.views import obtain_jwt_token

urlpatterns = [
    url(r'^本身的路由/', obtain_jwt_token),
]

而後咱們就能夠經過本身添加的路由並經過post添加username和password來獲取到token了,在進行訪問頁面的時候咱們只須要在請求頭中添加一個:Authorization: JWT <your_token>,就能夠獲得驗證了。
固然咱們可能不止只須要token數據,還須要用戶的ID,暱稱等信息,那麼咱們就須要手動生成token數據。服務器

from rest_framework_jwt.settings import api_settings
    
    jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
    jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
    
    payload = jwt_payload_handler(user)    #這裏的用戶對象就是在登陸視圖中獲取到的user
    token = jwt_encode_handler(payload)

固然咱們前面已經說明payload中最好不要存儲私密信息,因此咱們在處理user前須要將不須要的字段刪除:cookie

del user.set_password('')    #固然這樣作確定不科學,可是咱們因爲這裏沒有場景,因此我先這樣作,有須要的同窗能夠私聊我。

而後咱們能夠將返回到前端的數據進行保存,方便下次訪問攜帶:
前端響應中使用的代碼格式
關於session和local存儲:https://www.cnblogs.com/st-le...

sessionStorage.變量名 = 變量值   // 保存數據
sessionStorage.變量名  // 讀取數據
sessionStorage.clear()  // 清除全部sessionStorage保存的數據

localStorage.變量名 = 變量值   // 保存數據
localStorage.變量名  // 讀取數據
localStorage.clear()  // 清除全部localStorage保存的數據

最後利用localStorage與sessionStorage讀取數據的方式在須要後端驗證的地方添加token數據。
全部配置參考:

JWT_AUTH = {
    'JWT_ENCODE_HANDLER':
    'rest_framework_jwt.utils.jwt_encode_handler',    #加密處理函數

    'JWT_DECODE_HANDLER':
    'rest_framework_jwt.utils.jwt_decode_handler',    #解密處理函數

    'JWT_PAYLOAD_HANDLER':
    'rest_framework_jwt.utils.jwt_payload_handler',    #指定自定義函數以生成令牌有效內容

    'JWT_PAYLOAD_GET_USER_ID_HANDLER':
    'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler',    #若是您的存儲username方式與默認的有效負載處理程序不一樣,請實現此功能以username從有效負載中獲取

    'JWT_RESPONSE_PAYLOAD_HANDLER':        #負責控制登陸或刷新後返回的響應數據。覆蓋以返回自定義響應
    'rest_framework_jwt.utils.jwt_response_payload_handler',

    'JWT_SECRET_KEY': settings.SECRET_KEY,    #使用系統全局的SECRET_KEY
    'JWT_GET_USER_SECRET_KEY': None,    #這是JWT_SECRET_KEY的更強大版本。它是根據用戶定義的,所以若是令牌被泄露,能夠由全部者輕鬆更改。更改此值將使給定用戶的全部令牌都沒法使用。值應該是一個函數,接受用戶做爲惟一參數並返回它的密鑰。
    'JWT_PUBLIC_KEY': None,
    'JWT_PRIVATE_KEY': None,
    'JWT_ALGORITHM': 'HS256',    #加密算法,必須設置爲一個RS256,RS384或RS512。
    'JWT_VERIFY': True,
    'JWT_VERIFY_EXPIRATION': True,
    'JWT_LEEWAY': 0,
    'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300),    #設置有效期
    'JWT_AUDIENCE': None,
    'JWT_ISSUER': None,    #這是一個字符串,將根據iss令牌字段進行檢查。默認是None(不要檢查issJWT)
    'JWT_ALLOW_REFRESH': False,
    'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),    #設置令牌刷新時間,默認爲datetime.timedelta(days=7)(7天)

    'JWT_AUTH_HEADER_PREFIX': 'JWT',    #您能夠修改須要與令牌一塊兒發送的Authorization標頭值前綴。默認值爲JWT,用於令牌和受權標頭的另外一個常見值是Bearer。

    'JWT_AUTH_COOKIE': None,    #驗證Authorization標頭同時也驗證cookie,通常不用

}

本文參考:https://lion1ou.win/2017/01/18/

相關文章
相關標籤/搜索