天天看點

跟我一起學Go系列:Go gRPC 安全認證方式-Token和自定義認證

Go gRPC 安全認證方式-Token和自定義認證

Go gRPC 系列:

跟我一起學Go系列:gRPC安全認證機制-SSL/TLS認證

跟我一起學 Go 系列:gRPC 攔截器使用

跟我一起學 Go 系列:gRPC 入門必備

接上一篇繼續講 gRPC 認證,本篇内容主要是 Token 認證和自定義認證方式的使用。

說 Token 認證就不得不提 Session。做 Web 端開發的同學應該都了解 Session 和 Token 機制。

Session 一般由服務端存儲,使用者通過使用者名和密碼登入之後服務端會在伺服器開辟一塊 Session 記憶體空間存入使用者資訊,同時伺服器會在 cookie 資訊中寫入一個 Session_id 值,用于辨別這一塊記憶體空間。下次使用者再來請求的時候會由 cookie 中帶過來這個 Session_id,服務端拿着這個 Session_id 去尋找對應的 Session,如果能找到說明使用者已經登入過,不用重新走授權的邏輯。

使用 Session 存在問題在哪裡:

服務端存儲壓力過大,當使用者量大的時候,所有使用者都會在記憶體中儲存 Session 資訊,可想而知需要很大的記憶體空間。

分布式應用下 Session 共享問題會耗費更多的存儲。

Session 機制是基于 cookie 的,cookie 如果被截取使用者很容易受到 CSFR(跨站僞造請求攻擊)。

另外使用 cookie 的另一個弊端就是不支援跨域,當然對于跨域的處理現在已經不是什麼問題。

再來說說 Token 機制。token 即令牌的意思,令牌的生成規則是我們自定義的,使用者第一次登入後服務端生成一個令牌傳回給用戶端,以後用戶端在令牌過期内隻需要帶上這個令牌以及生成令牌必要的參數,服務端通過生成規則能生成一樣的令牌即表示校驗通過。

原理很簡單但是帶來的效果卻是翻倍提升的:

采用生成規則校驗,服務端無需存儲 token 資料,沒有記憶體壓力,同樣服務端做負載均衡的時候也無需像 session 那樣需要考慮分布式存儲問題。

支援跨域,将 token 置于請求頭中即可。

對于移動端這種不支援 cookie 的應用場景來說 token 是更有效的驗證手段。

Token 形式多種多樣,其中,JSON Web Token 是一種比較受歡迎的 Token 規範,其實就是規範 token 該怎麼生成的方式。

JWT 中的 Token 分為 3 部分,Header、Payload 與 Signature,例如:

兩個<code>.</code>字元隔開三部分,即:

含義上,Header表示 Token 相關的基本元資訊,如 Token 類型、加密方式(算法)等,具體如下(<code>alg</code>是必填的,其餘都可選):

<code>typ</code>:Token type

<code>cty</code>:Content type

<code>alg</code>:Message authentication code algorithm

Payload表示 Token 攜帶的資料及其它 Token 元資訊,規範定義的标準字段如下:

<code>iss</code>:Issuer,簽發方

<code>sub</code>:Subject,Token 資訊主題(Sub identifies the party that this JWT carries information about)

<code>aud</code>:Audience,接收方

<code>exp</code>:Expiration Time,過期時間

<code>nbf</code>:Not (valid) Before,生效時間

<code>iat</code>:Issued at,生成時間

<code>jti</code>:JWT ID,唯一辨別

這些字段都是可選的,Payload 隻要是合法 JSON 即可。生成之後的三部分又做了一次加密處理:

關于 JWT 規範的 Token 生成暫時就先說這麼多,我們接下來就看看在 gRPC 中如何應用 Token 機制。gRPC 本身不提供 Token 認證機制,而是通過插件機制支援第三方認證,本示例使用了第三方 jwt 包:

通過該包我們就不用自己去寫 jwt 規範下的這一套加密方式。

基于 JWT 規範的 Token 認證機制代碼位于 Gitbub倉庫,大家自行檢視。

首先我們建立一個新的測試 API,token.proto:

一個方法是登入的時候擷取服務端 token,一個方法模拟拿到服務端 token 之後是否能用 token 通過校驗。

接下來我們定義 token 的生成方式以及校驗方式,這裡使用了 第三方 JWT 元件:

CreateToken 方法調用了 jwt 生成 token 的規範,包括 token 的過期時間設定。

另一個重要的點是 AuthToken,它實作了 PerRPCCredentials 接口。gRPC 可以為每個方法的調用進行認證,進而對不同的使用者 token 進行不同的通路權限控制,首先需要實作 grpc.PerRPCCredentials 接口:

可以認為 PerRPCCredentials 接口就是 gRPC 提供的自定義認證方式的入口。注意到我在 GetRequestMetadata 方法中 set進去一個 authorization 字段,用來存儲 token。

JWT 認證方式實作完畢,我們可以寫服務端和用戶端的代碼:

服務端:

服務端在 Login 方法中要為使用者生成 token,是以調用了 CreateToken 方法。同樣 SayHello 方法中就要去校驗用戶端提供的 token 是否有效。

繼續看用戶端邏輯:

用戶端校驗分為兩個部分,Login 方法調用之前我們是不能加 token 校驗的,因為此刻還沒有拿到 token。

調用 Login 擷取到 Token 之後将 token set 進 metadata,重建立立連接配接,此後的調用就使用 token 來進行校驗。大家可以運作示例實驗一下。

上面 Token 校驗方式中說過,實作自定義校驗方式要實作 PerRPCCredentials 接口。Token 校驗本身就是一折特殊的自定義校驗方式,我們再來舉個示例:

先來看用戶端代碼:

自定義了一個 根據 appid 和 appkey 來校驗權限的功能,服務端檢查存在即放過。服務端代碼:

服務端校驗是否存在對應的 appid 和 appkey即可。了解了如何使用之後寫起來就很簡單。

關于 gRPC 安全認證方式就到這裡,兩篇内容分别講了基于 TLS 的認證和自定義認證的邏輯。大家根據業務場景自行決定使用哪種校驗即可。