在嗎?認識一下JWT(JSON Web Token) ?

什麼是JSON Web Token

官網介紹:html

JSON Web Token(JWT)是一個開放標準(RFC 7519),它定義了一種緊湊且自包含的方式,用於在各方之間安全地將信息做爲JSON對象傳輸。因爲此信息是通過數字簽名的,所以能夠被驗證和信任。可使用祕密(使用HMAC算法)或使用RSAECDSA的公用/專用密鑰對對JWT進行簽名前端

儘管能夠對JWT進行加密以在各方之間提供保密性,但咱們將重點關注已簽名的令牌。簽名的令牌能夠驗證其中包含的聲明的完整性,而加密的令牌則將這些聲明隱藏在其餘方的面前。當使用公鑰/私鑰對對令牌進行簽名時,簽名還證實只有持有私鑰的一方纔是對其進行簽名的一方。python

emmmm.......balabala一堆文字,那麼咱們來簡單總結下:web

JWT是一個JSON信息傳輸的開放標準,它可使用密鑰對信息進行數字簽名,以確保信息是可驗證和可信任的。算法

JWT的結構是什麼?

JWT由三部分構成:header(頭部)、payload(載荷)和signature(簽名)。 以緊湊的形式由這三部分組成,由「.「分隔。json

所以,JWT一般以下所示。後端

xxxxx.yyyyy.zzzzzapi

讓咱們把這串奇奇怪怪的東西分解開來:安全

header併發

header一般由兩部分組成:令牌的類型(即JWT)和所使用的簽名算法,例如HMAC SHA256或RSA等等。

例如:

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

顯而易見,這貨是一個json數據,而後這貨會被Base64編碼造成JWT的第一部分,也就是xxxxx.yyyyy.zzzzz中的xxxxxx

Payload

這貨是JWT的第二部分,叫載荷(負載),內容也是一個json對象,它是存放有效信息的地方,它能夠存放JWT提供的現成字段 :

  • iss: 該JWT的簽發者。

  • sub: 該JWT所面向的用戶。

  • aud: 接收該JWT的一方。

  • exp(expires): 何時過時,這裏是一個Unix時間戳。

  • iat(issued at): 在何時簽發的。

舉個例子:

{   "iss": "www.baidu.com",
  "sub": "you",   "aud": "me",
  "name": "456",
  "admin": true,   "iat": 1584091337,   "exp": 1784091337,
}

這貨一樣會被Base64編碼,而後造成JWT的第二部分,也就是xxxxx.yyyyy.zzzzz中的yyyyyy

Signature

這是JWT的第三部分,叫作簽名,此部分用於防止JWT內容被篡改。將上面的兩個編碼後的字符串都用英文句號.鏈接在一塊兒(頭部在前),就造成了

xxxxxx.yyyyyy

而後再使用header中聲明簽名算法進行簽名。 若是要使用HMAC SHA256算法,則將經過如下方式建立簽名:

HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

固然,在加密的時候,咱們還須要提供一個密鑰(secret),咱們能夠本身隨意指定。這樣就造成了JWT的第三部分,也就是xxxxx.yyyyy.zzzzz中的zzzzzz

最後,咱們把這三個部分拼在一塊兒,就造成了一個完整的JWT。

下面展現了一個完整的JWT,它先對header和payload進行編碼,最後用一個密鑰造成了簽名。

若是咱們想試驗一下的話,能夠在JWT的官網進行debugger。貼一下官網: https://jwt.io/

JSON Web Token認證流程

何時應該使用JSON Web Token?

如下是JSON Web Token 有用的一些狀況:

  • 受權:這是使用JWT的最多見方案。一旦用戶登陸,每一個後續請求將包括JWT,從而容許用戶訪問該令牌容許的路由,服務和資源。單一登陸是當今普遍使用JWT的一項功能,由於它的開銷很小而且能夠在不一樣的域中輕鬆使用。

  • 信息交換:JSON Web Token是在各方之間安全地傳輸信息的好方法。由於能夠對JWT進行簽名(例如,使用公鑰/私鑰對),因此您能夠肯定發件人是他們所說的人。此外,因爲簽名是使用標頭和有效負載計算的,所以您還能夠驗證內容是否遭到篡改。

那麼,有人就會說了,道理我都懂,我應該怎樣去實現呢?莫慌。。 

現?

接下來我會用python實現JWT,不想拉仇恨,可是,python大法好啊。。。。

在先後端分離的項目中,咱們須要與前端約定一種身份認證機制。當用戶登陸的時候,後端會生成token,而後返回給前端,前端須要將token拿到並按照必定規則放到header中,在下一次請求的時候一併發送給後端,後端進行token身份校驗。

這裏咱們約定前端請求後端服務時須要添加頭信息Authorization ,內容爲token。

我用的是fastapi web框架,搭建項目很是快。

from datetime import timedelta, datetime

import jwt
from fastapi import FastAPI, HTTPException, Depends
from starlette.status import HTTP_401_UNAUTHORIZED
from starlette.requests import Request
app = FastAPI()

SECRET_KEY = "sdifhgsiasfjaofhslio" # JWY簽名所使用的密鑰,是私密的,只在服務端保存
ALGORITHM = "HS256" # 加密算法,我這裏使用的是HS256
@app.get("/")
async def root():
    return {"message": "Hello World"}

@app.post("/create_token")
def create_token(username,password):
    if username == "123" and password == "123":
        access_token_expires = timedelta(minutes=60)
        expire = datetime.utcnow() + access_token_expires

        payload = {
                    "sub": username,
                    "exp": expire
                     }
        # 生成Token,返回給前端
        access_token = jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM)
        return {"access_token": access_token, "token_type": "bearer"}

    else:
        raise HTTPException(
            status_code=HTTP_401_UNAUTHORIZED,
            detail="username or password are not true",
            headers={"WWW-Authenticate": "Bearer"}
        )


def authorized_user(token):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        print(username)
        if username == "123":
            return username
    except jwt.PyJWTError:
        raise HTTPException(
        status_code=HTTP_401_UNAUTHORIZED,
        detail="認證失敗,無權查看",
        headers={"WWW-Authenticate": "Bearer"},)



@app.get("/app")
def create_token(request: Request):
    print(request.headers.get("host"), request.headers.get("Authorization"))
    user = authorized_user(request.headers.get("Authorization")) # 驗證Token
    if user:
        return {"username": user,"detail": "JWT經過,查詢成功"}

這裏,因爲現有的JWT庫已經幫咱們封裝好了,咱們可使用JWT直接生成 token,不用手動base64加密和拼接。

測試一下:

啓動項目以後,咱們打開http://127.0.0.1:8000/docs# ,就會看到如下咱們編寫好的api:

首先,咱們先驗證一下create_token接口

當咱們輸入用戶名,密碼後,後端進行驗證,驗證成功後會返回給前端一個token,也就是JWT。當前端拿到這個token以後,下次在請求的時候就必需要帶上這個token了,由於先後端已經約定好了。接下來咱們試一下:

認證失敗???

什麼緣由致使的呢??讓咱們點開檢查抓一下包看看:

恍然大悟,剛纔咱們說過,先後端事先約定好的,請求的header中必定要帶上token,在Authorization ,內容token。咱們如今這個請求的header中並無帶上token,那這種debug模式下又是改不了請求header信息的,咱們可使用接口測試工具進行測試,我主推Postman!!!,讓咱們來試一下:

至此,JWT介紹以及使用梳理完畢。

最後,感謝女友在生活中,工做上的包容、理解與支持 !

相關文章
相關標籤/搜索