如何設計實現一個輕量的開放API網關.
文章地址: https://blog.piaoruiqing.com/blog/2019/08/05/開放api網關實踐/
前言
隨著業(yè)務的發(fā)展, 所對接的第三方越來越多, 各個業(yè)務系統(tǒng)面臨著同樣一個問題: 如何讓第三方安全快速接入
. 此時有一個集驗簽雀久、鑒權宿稀、限流、降級等功能于一身的API網關服務變得尤為重要.
接下來將分享如何設計實現一個輕量級的API開放網關, 包括接口設計赖捌、數據庫設計祝沸、簽名驗簽方案、鑒權等. 本文側重于總體設計, 具體實現細節(jié)將陸續(xù)在后續(xù)的文章中分享.
API網關簡介
API網關在微服務中尤為重要, 其抽象了鑒權越庇、限流罩锐、降級等各個業(yè)務系統(tǒng)通用的功能. 作為眾多內部業(yè)務系統(tǒng)外的一層屏障.
基本需求
- 簽名及驗簽
- 鑒權
- 路由
- 權限及資源管理
總體設計
驗簽、鑒權等功能以職責鏈的方式進行處理, 網關根據配置進行路由并附加參數用以配合業(yè)務系統(tǒng)進行處理(如數據過濾等). 簡要請求處理流程如下:
接口設計
網關最基本的功能是轉發(fā)請求, 常見的方式是根據配置中的路由規(guī)則將請求轉發(fā)給內部服務, 如:
將/order/*
的請求轉發(fā)給內部的訂單系統(tǒng)卤唉、/user/*
的請求轉發(fā)給內部的用戶系統(tǒng), 這種做法常用于對整個業(yè)務系統(tǒng)負責的基礎網關.
而本文所設計的是服務于第三方的開放API網關
, 并未使用上述做法, 而是將請求的資源作為參數放到請求體中, 其原因如下:
- 開放API服務于第三方, 屏蔽內部路徑, 有利于提供命名統(tǒng)一且規(guī)范的接口.
- 請求接口的映射由網關的路由表維護, 內部接口升級甚至切換到新服務對外接口不變.
- 能夠更細粒度地針對接口進行權限控制涩惑、限流、統(tǒng)計等.
地址
開放API網關對外提供唯一入口, 具體請求的資源作為參數傳入.
公共參數
為了簡化簽名和驗簽的操作, 同時也提高靈活度, 唯一入口的約定了固定的公共參數和返回值, 如下:
公共請求參數
參數名稱 | 是否必須 | 類型 | 示例 | 備注 |
---|---|---|---|---|
app_id | 是 | string | 應用ID | |
method | 是 | string | aaa.bbb.ccc | 請求方法 |
charset | 是 | string | UTF-8 | 編碼 |
format | 是 | string | JSON | 業(yè)務參數格式 |
sign_type | 是 | string | RSA2 | 簽名類型 |
sign | 是 | string | 簽名 | |
timestamp | 是 | number | 1564929661796 | 時間戳, 單位: 毫秒 |
nonce | 是 | string | 63DCB93D270E44D49499F9E5D55705FE | 隨機字串(建議使用UUID) |
version | 是 | string | 1.0 | 接口版本 |
biz_content | 是 | string | {"start_time":"1564929661796", ...} | 請求業(yè)務參數 |
-
app_id
: 應用ID, 應用ID是授權的主體, 是調用方的身份標識 -
method
: 請求方法, 與內部URL對應, 由網關的路由表維護. -
timestamp
和nonce
用來防重放攻擊. -
biz_content
: 業(yè)務參數, 這個參數將轉發(fā)給內部業(yè)務系統(tǒng).
公共返回參數
參數名稱 | 是否必須 | 類型 | 示例 | 備注 |
---|---|---|---|---|
code | 是 | number | 0 | 錯誤碼 |
message | 否 | string | 錯誤信息 | |
charset | 是 | string | UTF-8 | 編碼 |
format | 是 | string | JSON | 返回參數格式 |
sign_type | 是 | string | RSA2 | 簽名類型 |
sign | 是 | string | 簽名 | |
timestamp | 是 | number | 時間戳, 單位: 毫秒 | |
biz_content | 是 | string | {"id":"1564929661796", ...} | 返回業(yè)務參數 |
-
biz_content
: 返回業(yè)務參數, 網關轉發(fā)業(yè)務系統(tǒng)的返回值.
[版權聲明]
本文發(fā)布于樸瑞卿的博客, 允許非商業(yè)用途轉載, 但轉載必須保留原作者樸瑞卿 及鏈接:blog.piaoruiqing.com. 如有授權方面的協(xié)商或合作, 請聯(lián)系郵箱: piaoruiqing@gmail.com.
簽名方案
調用方和服務方均生成2048
位RSA
秘鑰, 交換公鑰. 私鑰用于簽名, 公鑰用于驗簽, 開放API網關對外接口使用https
, 故暫不需額外做加密處理.
簽名算法
簽名算法名稱 | 標準簽名算法名稱 | 備注 |
---|---|---|
RSA2 | SHA256WithRSA | 強制要求 RSA 密鑰的長度至少為 2048 |
簽名規(guī)則
簽名參數內容
剔除sign
之后的全部參數.
簽名參數排序
按照參數名的ASCII
碼遞增排序(字母升序排序).
簽名生成方式
排序后的參數列表組合成參數名a=參數值a&參數名b=參數值b&...&參數名z=參數值z
的字符串, 并使用私鑰
生成sign
.
數據庫設計
數據庫用于存儲秘鑰權限等配置, 程序和數據庫之間有多級緩存用以提高訪問速度. 簡要ER圖如下:
-
app
: 調用方主體, 用于標識請求方身份. -
group
: 組,app
分組, 可通過group
統(tǒng)一進行授權. -
subject
: 主體(app/group). -
resource
: 資源, 維護請求資源與內部接口的映射關系,url
+http_method
對應唯一的resource_id.
技術選型
網關除了滿足功能上的需求外, 性能上的需求也需要著重考慮, 畢竟作為各個業(yè)務系統(tǒng)對外的唯一入口, 網關的性能可能會成為整個業(yè)務系統(tǒng)的瓶頸. 業(yè)務并不復雜, 性能要求高, 響應式編程正是一個不錯的選擇.
-
Spring WebFlux
+netty
: 響應式Web框架. -
Spring Data Reactive Redis
+Lettuce
: 響應式redis客戶端. -
Guava
: Google工具包, 使用LoadingCache
作為進程內緩存.
結語
網關作為內部系統(tǒng)外面的一層屏障和入口, 除基本功能和性能上的需求外, 監(jiān)控搬味、統(tǒng)計境氢、日志等都是需要考慮到的問題, 網關方面開源產品眾多, 但選擇時一定要考慮自身業(yè)務, 適合自身的前提下參考各個成熟的方案進行實踐.
系列文章:
歡迎關注公眾號: 代碼如詩
[版權聲明]
本文發(fā)布于樸瑞卿的博客, 允許非商業(yè)用途轉載, 但轉載必須保留原作者樸瑞卿 及鏈接:blog.piaoruiqing.com. 如有授權方面的協(xié)商或合作, 請聯(lián)系郵箱: piaoruiqing@gmail.com.