Skip to main content
Version: Next

JWT

用途說明#

使用包含HS256或是RS256簽署的JSON Web Tokens(參考RFC 7519)對請求做驗證。每一個用戶都會擁有JWT憑證(公開或祕密金鑰)可以用來簽署JWTs。 權杖可透過下列方式傳送:

  • 查詢字串(query string)
  • Cookie
  • HTTP 請求標頭

欄位配置說明#

變數類型預設值說明必填
uri_param_namesarray of stringjwt查詢字串的列表,API Manager會審查並從中取得JWTs。
cookie_namesarray of stringcookie的列表,API Manager會審查並從中取得JWTs。
header_namesarray of stringauthorizationHTTP標頭的列表,API Manager會審查並從中取得JWTs。
claims_to_verifyarray of string標準聲明內容列表使API Manager可以識別。可接受的項目有 exp 以及 nbf
key_claim_namestringiss代表憑證中 key 的聲明名稱。插件會嘗試從JWT payload或是header以此順序讀取此聲明。
secret_is_base64booleanfalse開啟此項目,則插件會將憑證之祕鑰以base64做編碼。可以建立一個編碼過的祕鑰給用戶,用原本的祕鑰簽署JWT。V
anonymousstring可設定"anonymous"使用者在驗證失敗時會使用此身份驗證。如此欄位為空,則請求之標頭沒帶上Authorization時會收到authentication failure 4xx的回應。要注意的是,此欄位需填入的是consumer本身之id,而不是custom_id。
run_on_preflightbooleantrue開啟此項設定會驗證preflight請求;關閉此項設定則會讓所有preflight請求通過。V
maximum_expirationnumber0可設定0至31536000(365天)做為JWT的存活時間(單為為秒)。超過範圍的數字會收到拒絕訊息(HTTP狀態碼403)。如果設定此欄位,則在 claims_to_verify 中也必須填入 exp 的內容。 0 代表無限期。

用法示例#

在全局啟用插件#

  1. 從網站左邊Menu中 外掛插件 頁面中,點選右上角的 新增外掛插件

全局啟用畫面

  1. 點選後,選擇 認證 頁籤,並啟用JWT,填寫內容參考欄位配置說明,設定成功後,任何請求(不分服務、路由、用戶)皆需經過認證才能通過。

在服務端上啟用插件#

  1. 從網站左邊Menu中 服務 > 服務列表 頁面中,選擇要啟用此插件的服務,假設為google,點選對應的編輯按鈕:

服務啟用畫面1

  1. 在編輯畫面中,點選上方的 外掛插件 頁籤,再點選頁籤內容上方的 新增外掛插件 按鈕:

服務啟用畫面2

點選後,選擇 認證 頁籤,並啟用JWT,填寫內容參考欄位配置說明,設定成功後,僅有此服務(範例為google)請求需經過認證才能通過。

在路由端上啟用插件#

可以由兩種方式來選擇路由,並啟用插件:

方式一:路由列表#

  1. 從網站左邊Menu中 服務 > 路由列表 頁面中,選擇要啟用此插件的路由,假設為google,點選對應的編輯按鈕:

路由啟用畫面1

方式二:服務 > 服務列表 > 路由列表#

  1. 從網站左邊Menu中 服務 > 服務列表 頁面中,選擇要啟用此插件的路由 所屬之服務(假設為google),點選對應的編輯按鈕。

在編輯畫面中,點選上方的 路由 頁籤,選擇要啟用此插件的路由(假設為google),點選對應的編輯按鈕:

路由啟用畫面2


  1. 承第1步,點擊上述兩種方式之一的編輯按鈕後,在編輯畫面中,點選上方的 外掛插件 頁籤,再點選頁籤內容上方的 新增外掛插件 按鈕:

路由啟用畫面3

點選新增外掛插件 按鈕後,選擇 認證 頁籤,並啟用JWT,填寫內容參考欄位配置說明,設定成功後,僅有此路由(範例為google)請求需經過認證才能通過。

建立使用者及憑證#

  1. 從網站左邊Menu中 訂閱用戶 > 用戶列表 頁面中選擇右上方 新增 按鈕,新增用戶。

  2. 選擇剛建立的使用者,進入編輯頁面,選擇上方 憑證 頁籤,然後選擇左邊 JWT 頁籤,再選擇列表左上方的 新增 按鈕。

jwt

  1. 演算法部分可填入 HS256HS384HS512RS256ES256 。其它像金鑰欄位可以填入自己的金鑰或是留空自動生成,而RSA公開金鑰在演算法選擇 RS256 或是 ES256 時,必須填入公開金鑰(PEM格式)用來驗證權杖的簽署。如果演算法選擇 HS256 或是 ES256 則使用祕鑰簽署JWTs憑證,但祕鑰欄位如果留空會自動生成新的祕鑰。
  • 如選擇演算法 HS256

jwt2 jwt3

  • 如選擇演算法 RS256

jwt4 jwt5

驗證#

  1. 選擇一路由開啟此插件服務,並建立好使用者及憑證 (範例為將路由之域名設定為 google,路徑設定為 /index,並開啟 拆分路徑)。

  2. 此時在console上送出以下指令

$ curl -H 'x-api-host: google' http://localhost:8000/index -i

會得到以下回應

HTTP/1.1 401 Unauthorized
Date: Thu, 25 Mar 2021 07:56:13 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
WWW-Authenticate: Basic realm="kong"
Content-Length: 26
X-Kong-Response-Latency: 1
Server: kong/2.0.4
{"message":"Unauthorized"}

代表插件正常運作,並阻擋未通過驗證之請求。

使用祕鑰建立JWT(HS256)#

  1. JWT分為三個部分:header、payload、secret。

    1. header設定為
    {
    "typ": "JWT",
    "alg": "HS256"
    }
    1. payload的部分,需要包含 key_claim_name 的值,預設為 iss 。 將其值設定為剛建立的憑證產生的金鑰。
    {
    "iss": "x70Cz68T3HmtPJ3IytJpN96s8a10Np3X"
    }
    1. secret即為剛剛建立的憑證產生的祕鑰,並將以上三個部分使用JWT官網生成JWT權杖
    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ4NzBDejY4VDNIbXRQSjNJeXRKcE45NnM4YTEwTnAzWCJ9.ayu7BkjmWLxWHV6iW_lxHx2OyqKQh0v4c_HvjGGHicw
  2. 之後送出請求時代入JWT權杖

$ curl -H 'x-api-host: google' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ4NzBDejY4VDNIbXRQSjNJeXRKcE45NnM4YTEwTnAzWCJ9.ayu7BkjmWLxWHV6iW_lxHx2OyqKQh0v4c_HvjGGHicw' http://localhost:8000/index -i

即可得到正常的回應。

如果有設定 uri_param_names 也可用下列方式送出請求

$ curl -H 'x-api-host: google' 'http://localhost:8000/index?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ4NzBDejY4VDNIbXRQSjNJeXRKcE45NnM4YTEwTnAzWCJ9.ayu7BkjmWLxWHV6iW_lxHx2OyqKQh0v4c_HvjGGHicw' -i

使用公開/祕密金鑰建立JWT(RS256/ES256)#

  1. JWT分為三個部分:header、payload、secret。

    1. header設定為
    {
    "typ": "JWT",
    "alg": "RS256"
    }
    1. payload的部分,需要包含 key_claim_name 的值,預設為 iss 。 將其值設定為剛建立的憑證產生的金鑰。
    {
    "iss": "J5fXgnWycvlwZsZdp4d5FZj04IZZu6AC"
    }
    1. 使用JWT官網代入以上兩個資訊,再加上公開及祕密金鑰內容後生成JWT權杖
    eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJKNWZYZ25XeWN2bHdac1pkcDRkNUZaajA0SVpadTZBQyJ9.FAvPN4MQsL9_PDYut6_oOte07hdfyomdw7HSAO49wMG2QgAqEB0YofQHtesX7QpP2zvdiCo_uQC9uYvviiqnTTJO5oP0XBWSXBEFaXuQ3ey3Sh8Jp5wbB0F6q8kuCbQn7-elM8Rp0RAwIYnTwprUShCtZ4gtw2SjrFib3mvsOg7y5t4ChUOuCh0NbGhvyqJPItdPT9-HYMsp8ILjdrDtkH7afXCXsTBTfbIozpWSj1PLDKS8RlbKdguBSebM51FQlYueMf5JLm6GUYVRcDBHi-zwRNqASh-qC_eUcPcbnjssNWMoePCtPJuuPg-qGwlP8ExznrUA_-BXDGbITV-zVw
  2. 之後送出請求時代入JWT權杖

$ curl -H 'x-api-host: google' -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJKNWZYZ25XeWN2bHdac1pkcDRkNUZaajA0SVpadTZBQyJ9.FAvPN4MQsL9_PDYut6_oOte07hdfyomdw7HSAO49wMG2QgAqEB0YofQHtesX7QpP2zvdiCo_uQC9uYvviiqnTTJO5oP0XBWSXBEFaXuQ3ey3Sh8Jp5wbB0F6q8kuCbQn7-elM8Rp0RAwIYnTwprUShCtZ4gtw2SjrFib3mvsOg7y5t4ChUOuCh0NbGhvyqJPItdPT9-HYMsp8ILjdrDtkH7afXCXsTBTfbIozpWSj1PLDKS8RlbKdguBSebM51FQlYueMf5JLm6GUYVRcDBHi-zwRNqASh-qC_eUcPcbnjssNWMoePCtPJuuPg-qGwlP8ExznrUA_-BXDGbITV-zVw' http://localhost:8000/index -i

即可得到正常的回應。

如果有設定 uri_param_names 也可用下列方式送出請求

curl -H 'x-api-host: google' 'http://localhost:8000/index?jwt=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJKNWZYZ25XeWN2bHdac1pkcDRkNUZaajA0SVpadTZBQyJ9.FAvPN4MQsL9_PDYut6_oOte07hdfyomdw7HSAO49wMG2QgAqEB0YofQHtesX7QpP2zvdiCo_uQC9uYvviiqnTTJO5oP0XBWSXBEFaXuQ3ey3Sh8Jp5wbB0F6q8kuCbQn7-elM8Rp0RAwIYnTwprUShCtZ4gtw2SjrFib3mvsOg7y5t4ChUOuCh0NbGhvyqJPItdPT9-HYMsp8ILjdrDtkH7afXCXsTBTfbIozpWSj1PLDKS8RlbKdguBSebM51FQlYueMf5JLm6GUYVRcDBHi-zwRNqASh-qC_eUcPcbnjssNWMoePCtPJuuPg-qGwlP8ExznrUA_-BXDGbITV-zVw' -i

相關解釋#

聲明#

claims_to_verify 可支援 exp 以及 nbf 兩個選項,想要同時加入時可填入 exp,nbf

聲明名稱驗證內容
expJWT的過期時間,過期時間必須大於簽發JWT時間
nbf擬發放JWT之後,在某段時間點前該JWT仍舊是不可用的

Base64編碼祕鑰#

如果祕鑰中含有binary資料,可以將它們以base64做編碼。這時候要將 secret_is_base64 打開。在用戶底下建立憑證的時候必須將已編碼過的祕鑰代入祕鑰的欄位。而在建立JWT時則要使用原始的祕鑰。

生成公開/祕密金鑰#

想生成全新的公開及祕密金鑰,可使用下列指令

$ openssl genrsa -out private.pem 2048

生成祕密金鑰後,再生成相應的公開金鑰

$ openssl rsa -in private.pem -outform PEM -pubout -out public.pem

之後就會生成兩把金鑰分別在 public.pemprivate.pem