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

什麼是JSON Web Token

官網介紹:

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

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

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

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

JWT的結構是什麼?

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

因此,JWT通常如下所示。

xxxxx.yyyyy.zzzzz

讓我們把這串奇奇怪怪的東西分解開來:

header

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

例如:

<code>{  "alg": "HS256", "typ": "JWT" }/<code>

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

Payload

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

  • iss: 該JWT的簽發者。
  • sub: 該JWT所面向的用戶。
  • aud: 接收該JWT的一方。
  • exp(expires): 什麼時候過期,這裡是一個Unix時間戳。
  • iat(issued at): 在什麼時候簽發的。

舉個例子:

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

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

Signature

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

<code>xxxxxx.yyyyyy
/<code>

然後再使用header中聲明簽名算法進行簽名。 如果要使用HMAC SHA256算法,則將通過以下方式創建簽名:

<code>HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)/<code>

當然,在加密的時候,我們還需要提供一個密鑰(secret),我們可以自己隨意指定。這樣就形成了JWT的第三部分,也就是xxxxx.yyyyy.zzzzz中的zzzzzz

最後,我們把這三個部分拼在一起,就形成了一個完整的JWT。

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

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

如果我們想試驗一下的話,可以在JWT的官網進行debugger。貼一下官網: https://jwt.io/

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

JSON Web Token認證流程

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

什麼時候應該使用JSON Web Token?

以下是JSON Web Token 有用的一些情況:

  • 授權:這是使用JWT的最常見方案。一旦用戶登錄,每個後續請求將包括JWT,從而允許用戶訪問該令牌允許的路由,服務和資源。單一登錄是當今廣泛使用JWT的一項功能,因為它的開銷很小並且可以在不同的域中輕鬆使用。
  • 信息交換:JSON Web Token是在各方之間安全地傳輸信息的好方法。因為可以對JWT進行簽名(例如,使用公鑰/私鑰對),所以您可以確定發件人是他們所說的人。此外,由於簽名是使用標頭和有效負載計算的,因此您還可以驗證內容是否遭到篡改。

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

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

如何實現?

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

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

這裡我們約定前端請求後端服務時需要添加頭信息Authorization ,內容為token。

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

<code>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通過,查詢成功"}/<code>

這裡,由於現有的JWT庫已經幫我們封裝好了,我們可以使用JWT直接生成 token,不用手動base64加密和拼接。

測試一下:

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

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

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

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

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

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

認證失敗???

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

什麼原因導致的呢??讓我們點開檢查抓一下包看看:

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

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

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

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

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



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


分享到:


相關文章: