基于 OpenResty 的短信驗(yàn)證碼平臺(tái)接口網(wǎng)關(guān)設(shè)計(jì)
來源:原創(chuàng) 時(shí)間:2017-10-13 瀏覽:0 次
本文講述基于 OpenResty 的
短信驗(yàn)證碼平臺(tái)接口關(guān)設(shè)計(jì),主要談及接口網(wǎng)關(guān)的請(qǐng)求路由與安全認(rèn)證(IP 與 URI 白名單、加解密與驗(yàn)簽名流程等)這兩部分內(nèi)容,其中涉及到的 Nginx、OpenResty 等相關(guān)內(nèi)容會(huì)作簡(jiǎn)單介紹。
談?wù)劵?OpenResty 的接口網(wǎng)關(guān)設(shè)計(jì)
〇、前言
一、什么是接口網(wǎng)關(guān)
1.1 定位
1.2 功能
二、為什么需要接口網(wǎng)關(guān)
2.1 請(qǐng)求路由
2.2 安全認(rèn)證
三、如何開發(fā)接口網(wǎng)關(guān)
3.2.1 兩層 HAProxy 代理
3.2.2 接口網(wǎng)關(guān)
3.2.3 架構(gòu)總結(jié)
3.2.2.1 主流程設(shè)計(jì)
3.2.2.2 配置服務(wù)設(shè)計(jì)
3.2.2.3 安全服務(wù)設(shè)計(jì)
3.1.1 Nginx 簡(jiǎn)介
3.1.1 OpenResty 簡(jiǎn)介
3.1 Nginx 與 OpenResty 簡(jiǎn)介
3.2 接口網(wǎng)關(guān)的架構(gòu)
〇、前言
筆者曾參與開發(fā)兩個(gè)
短信驗(yàn)證碼平臺(tái)接口網(wǎng)關(guān)的項(xiàng)目,一個(gè)是基于 Tomcat 的應(yīng)用提供的網(wǎng)關(guān)服務(wù),另一個(gè)是基于 OpenResty 的 Nginx 應(yīng)用提供的網(wǎng)關(guān)服務(wù)。經(jīng)過兩個(gè)網(wǎng)關(guān)項(xiàng)目的開發(fā),筆者在接口網(wǎng)關(guān)開發(fā)方面稍微積累了一些經(jīng)驗(yàn),故在此把這些經(jīng)驗(yàn)分享出來一起交流學(xué)習(xí)。由于基于 OpenResty 的 Nginx 網(wǎng)關(guān)普遍被認(rèn)為是更優(yōu)的方案,故本文主要針對(duì)基于 OpenResty 的 Nginx 網(wǎng)關(guān)進(jìn)行講述。當(dāng)然,由于不同的并發(fā)數(shù)量級(jí),不同的業(yè)務(wù)場(chǎng)景,接口網(wǎng)關(guān)的設(shè)計(jì)多種多樣,本文所述其中較為簡(jiǎn)單且輕量級(jí)的一種。
注:由于筆者經(jīng)驗(yàn)與知識(shí)有限,文章中如有錯(cuò)誤或偏頗,歡迎探討和指正(作業(yè)部落提供文章按塊批注功能,非常歡迎提批注,筆者會(huì)及時(shí)修正)。
一、什么是接口網(wǎng)關(guān)
1.1 定位
接口網(wǎng)關(guān),顧名思義,是企業(yè) IT 在系統(tǒng)邊界上提供給外部訪問內(nèi)部接口服務(wù)的統(tǒng)一入口。這里的外部可以指客戶端、瀏覽器或者第三方應(yīng)用等,在這種情況下,接口網(wǎng)關(guān)可以有多種定位:
提供后端服務(wù)面向 Web App 或者 Mobile App 的 APIGateway
作為開放平臺(tái)面向 Partner 的 OpenAPI
...
在筆者的工作中,同樣把面向客戶端的網(wǎng)關(guān)稱作 APIGateway,把作為開放平臺(tái)提供給第三方服務(wù)的網(wǎng)關(guān)稱作 OpenApi。本文主要以 OpenApi 作為接口網(wǎng)關(guān)為例來講述。
1.2 功能
作為企業(yè) IT 系統(tǒng)的統(tǒng)一入口,接口網(wǎng)關(guān)可提供請(qǐng)求路由與組合、協(xié)議轉(zhuǎn)換、安全認(rèn)證、服務(wù)鑒權(quán)、流量控制與日志監(jiān)控等服務(wù)。在筆者的工作中,主要在接口網(wǎng)關(guān)上實(shí)現(xiàn)了請(qǐng)求路由與安全認(rèn)證的功能,題目中所說的“設(shè)計(jì)”,主要是指請(qǐng)求路由與安全認(rèn)證方面,暫不涉及流量控制或日志監(jiān)控等其他方面的設(shè)計(jì)。
二、為什么需要接口網(wǎng)關(guān)
正如上文所言,
短信驗(yàn)證碼平臺(tái)接口為企業(yè)應(yīng)用提供了豐富的功能,而筆者在工作中開發(fā)的接口網(wǎng)關(guān)主要提供請(qǐng)求路由與安全認(rèn)證的功能,那么在回答“為什么需要接口網(wǎng)關(guān)”的時(shí)候,需要對(duì)這兩者多加闡述。
2.1 請(qǐng)求路由
企業(yè)提供內(nèi)外兩網(wǎng),在沒有接口網(wǎng)關(guān)時(shí),提供外部服務(wù)的應(yīng)用需要部署在外網(wǎng)。隨著服務(wù)的增多,部署在外網(wǎng)的應(yīng)用越來越多,在服務(wù)的安全壓力與維護(hù)成本增大的情況下,需要一個(gè)統(tǒng)一的接口網(wǎng)關(guān)“隔離”內(nèi)外服務(wù)。企業(yè)提供的服務(wù)(無論內(nèi)部服務(wù)還是外部服務(wù))均部署在內(nèi)網(wǎng),而由部署在外網(wǎng)的網(wǎng)關(guān)接受請(qǐng)求,并路由到內(nèi)網(wǎng)服務(wù)。在這種情況下,既有利于對(duì)外屏蔽企業(yè)內(nèi)部服務(wù)部署細(xì)節(jié),提供統(tǒng)一的服務(wù)訪問地址,又便于管理與維護(hù)內(nèi)外部服務(wù)接口,便于演進(jìn)與重構(gòu)服務(wù)。這是接口網(wǎng)關(guān)提供請(qǐng)求路由的作用。
2.2 安全認(rèn)證
在沒有接口網(wǎng)關(guān)時(shí),企業(yè)對(duì)外服務(wù)直接由外部訪問,身份驗(yàn)證與數(shù)據(jù)加解密等工作都需要每一個(gè)對(duì)外服務(wù)本身去處理,增加了服務(wù)本不該有的職責(zé),并且增加了服務(wù)開發(fā)的難度與工作量。實(shí)際在大多數(shù)情況下,可以將身份驗(yàn)證與數(shù)據(jù)加解密等安全工作可以從服務(wù)抽離,統(tǒng)一由接口網(wǎng)關(guān)負(fù)責(zé)處理。接口網(wǎng)關(guān)作為入口,對(duì)外驗(yàn)證調(diào)用方的 IP,身份以及接口訪問權(quán)限等,并且可以解密數(shù)據(jù)后再將請(qǐng)求路由到服務(wù)。這是接口網(wǎng)關(guān)提供安全認(rèn)證的功能。
以上是實(shí)際工作中涉及的為什么需要接口網(wǎng)關(guān)的其中兩個(gè)原因,當(dāng)然原因遠(yuǎn)不止此,有興趣的讀者可以閱讀其他文章,比如 《談API網(wǎng)關(guān)的背景、架構(gòu)以及落地方案》 或者 《微服務(wù):從設(shè)計(jì)到部署》(英文原文:Microservices: From Design to Deployment)。接下來的章節(jié)我們開始探討如何開發(fā)接口網(wǎng)關(guān)。
三、如何開發(fā)接口網(wǎng)關(guān)
我們先看看工作中設(shè)計(jì)的提供請(qǐng)求路由與安全認(rèn)證功能的接口網(wǎng)關(guān)的架構(gòu)。
不過在介紹接口網(wǎng)關(guān)的設(shè)計(jì)之前,我們先來了解一下關(guān)于 Nginx 與 OpenResty 的基礎(chǔ)知識(shí)。
3.1 Nginx 與 OpenResty 簡(jiǎn)介
3.1.1 Nginx 簡(jiǎn)介
Nginx 是世界第二大 Web 服務(wù)器,僅次于 Apache,然而由于其極高的性能可處理海量的互聯(lián)網(wǎng)請(qǐng)求,現(xiàn)在已經(jīng)成為業(yè)界高性能 Web 服務(wù)器的代名詞。
它的主要特征是高性能、高擴(kuò)展性、高可靠性、低內(nèi)存消耗、單機(jī)支持 10 萬以上的并發(fā)連接,支持熱部署,以及使用較自由的 BSD 許可協(xié)議。其中,Nginx 可以處理高并發(fā)壓力下的并發(fā)請(qǐng)求的原因如下:
事件驅(qū)動(dòng)模型設(shè)計(jì)
全異步的網(wǎng)絡(luò) I/O 處理機(jī)制
極少的進(jìn)程切換
內(nèi)存消耗低,極度“壓榨”服務(wù)器硬件資源
除了基于事件驅(qū)動(dòng)的架構(gòu)使其支持百萬級(jí)的 TCP 連接,另外高度模塊化的設(shè)計(jì)和自由的許可證使其擁有非常多擴(kuò)展其功能的第三方模塊,也是它的重要特性。所以,后來才會(huì)有 OpenResty 的誕生。
我們看一個(gè) Nginx 作簡(jiǎn)單配置來提供服務(wù)的例子:
worker_processes 1;
events {
worker_connections 1024;
}
http {
upstream backend {
server 127.0.0.1:8080
}
server {
location /back {
proxy_pass http://backend;
}
}
}
上述配置文件中,分別在 event、http、server 以及 location 塊配置項(xiàng)中做了一些簡(jiǎn)單的配置,當(dāng)安裝完并啟動(dòng) Nginx后(監(jiān)聽 80 端口),訪問到 /back 路徑下的請(qǐng)求會(huì)被轉(zhuǎn)發(fā)到本地 127.0.0.1:8080 服務(wù)上。
3.1.1 OpenResty 簡(jiǎn)介
根據(jù)官網(wǎng)定義,OpenResty 是一個(gè)通過 Lua 擴(kuò)展 Nginx 實(shí)現(xiàn)的可伸縮的 Web 平臺(tái)。其核心是基于 Nginx 一個(gè) C 模塊將 Lua 語言嵌入到 Nginx 服務(wù)器中,對(duì)外提供一套完整的 Lua Web 的 API,并透明支持非阻塞 I/O,提供協(xié)程 —— “輕量級(jí)線程”、定時(shí)器等,從而極大地降低了高性能服務(wù)端的開發(fā)難度和開發(fā)周期。
OpenResty 將兩個(gè)極為優(yōu)秀的組件 Nginx 與 Lua 進(jìn)行糅合,一方面保留了 Nginx 高性能 web 服務(wù)特征,另一方面有提供 Lua 特性在極少損失性能情況下便于業(yè)務(wù)功能的開發(fā)。根據(jù)官網(wǎng)介紹,OpenResty 非常便于用來搭建能夠處理超高并發(fā)、擴(kuò)展性極高的動(dòng)態(tài) Web 應(yīng)用、Web 服務(wù)和動(dòng)態(tài)網(wǎng)關(guān)。
我們也是因?yàn)?OpenResty 的這些特性,特別是它對(duì)搭建動(dòng)態(tài)網(wǎng)關(guān)的友好支持,才選擇了基于 OpenResty 來開發(fā)我們的接口網(wǎng)關(guān) —— APIGateway 與 OpenApi。
開發(fā)接口網(wǎng)關(guān)使用到的 OpenResty 一個(gè)重要知識(shí):OpenResty 對(duì)于一個(gè)請(qǐng)求的處理流程。Nginx 把一個(gè)請(qǐng)求分為不同的階段,從而讓第三方模塊通過掛載行為在不同的階段來定制自己的行為;OpenResty 擁有同樣的特性,不過在不同階段掛載的是 Lua 腳本。下圖是基于《OpenResty 最佳實(shí)踐》原圖重繪而來:
從上圖可知,OpenResty 處理請(qǐng)求大致分為四個(gè)階段:
初始化階段(Initialization Phase)
重寫與訪問階段(Rewrite / Access Phase)
內(nèi)容生成階段(Content Phase)
日志記錄階段(Log Phase)
我們看一個(gè) OpenResty 作簡(jiǎn)單配置來提供服務(wù)的例子:
worker_processes 1;
events {
worker_connections 1024;
}
http {
resolver 127.0.0.1;
lua_package_path '$prefix/lua/?.lua;;';
init_by_lua_block {
# ...
}
init_worker_by_lua_file lua/init_work_by_lua.lua;
server {
listen 80;
location / {
rewrite_by_lua_file lua/rewrite_by_lua.lua;
access_by_lua_file lua/access_by_lua.lua;
proxy_pass http://<url>;
}
}
}
上述配置文件中,分別在 event、http、server 以及 location 塊配置項(xiàng)中做了一些簡(jiǎn)單的配置,當(dāng)安裝完并啟動(dòng) Nginx后(監(jiān)聽 80 端口),首先執(zhí)行 init_by_lua_block、init_worker_by_lua_file 進(jìn)行初始化,接著接受請(qǐng)求,所有的請(qǐng)求都會(huì)匹配上 "/" 路徑,進(jìn)而執(zhí)行 rewrite_by_lua_file、access_by_lua_file 進(jìn)行重寫與訪問,最后轉(zhuǎn)發(fā)請(qǐng)求到本地 127.0.0.1 服務(wù)上。
在實(shí)際的接口網(wǎng)關(guān)開發(fā)中,我們主要是使用到了 OpenResty 中初始化階段的 init_by_lua*、init_worker_by_lua*、重寫與訪問階段 的 rewrite_by_lua*、access_by_lua* 以及內(nèi)容生成階段 content_by_lua* 過程。
3.2 接口網(wǎng)關(guān)的架構(gòu)
這一節(jié)是本文的核心內(nèi)容,重點(diǎn)講述接口網(wǎng)關(guān)的架構(gòu)設(shè)計(jì)。如前文所述,本文主要以 OpenApi 為例來講述接口網(wǎng)關(guān)的架構(gòu)設(shè)計(jì)。先看圖:
下面我們來一步步來分析架構(gòu)圖的各個(gè)部分,首先是兩層的 HAProxy 。
3.2.1 兩層 HAProxy 代理
根據(jù)維基百科定義,HAProxy 是一個(gè)使用 C 語言編寫的自由及開放源代碼軟件,其提供高可用性、負(fù)載均衡,以及基于 TCP 和 HTTP 的應(yīng)用程序代理。
如圖所示,隔離的內(nèi)網(wǎng)與外網(wǎng)上分別提供了 HAProxy 代理, 外層暫且稱為 HAProxy internet ,內(nèi)層稱為 HAProxy internal。外層暴露于外網(wǎng)中,使用統(tǒng)一地址如 http://openapi.company.com 來接受外部請(qǐng)求(這里指第三方的請(qǐng)求);中間是基于 OpenResty 的 Nginx 網(wǎng)關(guān)層,外部請(qǐng)求經(jīng)過網(wǎng)關(guān)后通過 HAProxy internal 轉(zhuǎn)發(fā)到內(nèi)網(wǎng)的服務(wù)上,內(nèi)網(wǎng)服務(wù)遵循 Restful 風(fēng)格,網(wǎng)關(guān)轉(zhuǎn)發(fā)到內(nèi)網(wǎng)的地址由接口網(wǎng)關(guān)控制。
然而,目前的代理架構(gòu)受到了當(dāng)前整體架構(gòu)的約束,實(shí)際上兩層的 HAProxy 代理并不是必需的。
對(duì)于外層 HAProxy internet,由于我們使用了與 HAProxy 緊密結(jié)合的 Openshift 架構(gòu),所以多了一層 HAProxy 的轉(zhuǎn)發(fā);一般情況下,基于 OpenResty 的 Nginx 網(wǎng)關(guān)層可以直接在外網(wǎng)上提供服務(wù)。
對(duì)于內(nèi)層的 HAProxy internal,由于我們當(dāng)前還沒有實(shí)現(xiàn)服務(wù)治理,所以需要內(nèi)層的 HAProxy internal 進(jìn)行一層轉(zhuǎn)發(fā);當(dāng)實(shí)現(xiàn)了服務(wù)治理,可以消除內(nèi)層 HAProxy 代理,減少轉(zhuǎn)發(fā)消耗。
在我們當(dāng)前的系統(tǒng)量級(jí)下,這兩層 HAProxy 轉(zhuǎn)發(fā)消耗非常小可以被接受,所以調(diào)整架構(gòu)的優(yōu)先級(jí)還不高,以后再慢慢演進(jìn)。
3.2.2 接口網(wǎng)關(guān)
接下來這一節(jié)是最為重點(diǎn)的接口網(wǎng)關(guān)的設(shè)計(jì)。接口網(wǎng)關(guān)主要利用前文所述的 OpenResty 執(zhí)行階段對(duì)請(qǐng)求與響應(yīng)進(jìn)行流程處理,包括接口地址的重寫,IP 與資源白名單的控制,請(qǐng)求的解密與驗(yàn)簽,請(qǐng)求的路由以及響應(yīng)的簽名與加密等。
這里分成主流程,配置服務(wù),安全服務(wù)三部分進(jìn)行講述。
3.2.2.1 主流程設(shè)計(jì)
主流程是網(wǎng)關(guān)的核心,是請(qǐng)求處理的控制中心;它是通過 OpenResty 的 Lua 腳本處理流程來實(shí)現(xiàn)對(duì)請(qǐng)求的處理。
A. 主流程
在 OpenResty 服務(wù)啟動(dòng)之后,首先通過 init_by_lua_block 階段初始化常量(包括調(diào)用配置服務(wù)以及安全服務(wù)所需的主機(jī)地址、端口、URL 地址等)、引入依賴(包括常用的 http 以及 cjson 依賴等)等作為全局使用;
接著通過 init_worker_by_lua_file 階段設(shè)置定時(shí)任務(wù)調(diào)用內(nèi)網(wǎng)配置服務(wù)來緩存配置,為處理第三方的請(qǐng)求做準(zhǔn)備,其中加載的配置可供 URL 重寫(即接口映射)、IP 以及資源(URI)白名單限制、請(qǐng)求的解密驗(yàn)簽以及響應(yīng)的簽名加密使用,詳情查看配置服務(wù)一節(jié)。
當(dāng)?shù)谌秸?qǐng)求通過 HAProxy Internet 進(jìn)入到網(wǎng)關(guān)后,根據(jù)配置通過 rewrite_by_lua_file 階段做 URL 重寫(即接口映射)。
服務(wù)接口 URL 發(fā)生變更,為了兼容舊的第三方調(diào)用,需要重寫第三方請(qǐng)求 URL 到新服務(wù)接口上
Restful 接口的 Path Variable 在 Nginx 環(huán)境與在 Tomcat 環(huán)境上正則匹配的差異
需要重寫的原因可能有:
URL 重寫后,通過 access_by_lua_file 進(jìn)入訪問控制階段,此時(shí)根據(jù)授權(quán)的第三方 IP 白名單列表,授權(quán)予第三方的開放接口列表,校驗(yàn)請(qǐng)求的 IP 以及 URL。
IP 與 URI 校驗(yàn)通過后,同樣在 access_by_lua_file 階段根據(jù)配置調(diào)用內(nèi)網(wǎng)的安全服務(wù)進(jìn)行請(qǐng)求的解密與驗(yàn)簽,獲取明文。
在 content_by_lua_file 階段通過 ngx.location.capture 將原請(qǐng)求頭部信息以及參數(shù)等信息封裝到子請(qǐng)求中,借助子請(qǐng)求轉(zhuǎn)發(fā)原請(qǐng)求到開發(fā)接口服務(wù)中。
注意:根據(jù)官方文檔說明,ngx.location.capture 發(fā)送子請(qǐng)求會(huì)緩存響應(yīng)在內(nèi)存中,直到整個(gè)請(qǐng)求處理結(jié)束。那么,當(dāng)有響應(yīng)報(bào)文特別長(zhǎng)或者請(qǐng)求并發(fā)非常高時(shí),需要使用 cosocket 來替代 ngx.location.capture,避免因內(nèi)存不足造成網(wǎng)關(guān)服務(wù)失效。
同樣在 content_by_lua_file 階段根據(jù)配置調(diào)用安全服務(wù)進(jìn)行響應(yīng)的簽名與加密,獲取簽名與密文返回給第三方。
B. 文件結(jié)構(gòu)
項(xiàng)目的大致結(jié)構(gòu)如下,主要分為 Lua 代碼目錄和環(huán)境配置目錄。
--openapi
--lua
--access_by_lua.lua
--cache_management.lua
--content_by_lua.lua
--init_work_by_lua.lua
--rewrite_by_lua.lua
--security.lua
--prod
--Dockerfile
--nginx.conf
--sit
--Dockerfile
--nginx.conf
--README.md
C. 主流程在 conf 中的配置
# Nginx worker 進(jìn)程個(gè)數(shù),直接影響性能。
# 如果確認(rèn)不會(huì)出現(xiàn)阻塞式調(diào)用,那么有多少 CPU 內(nèi)核設(shè)置多少個(gè)進(jìn)程
# 如果有可能出現(xiàn)阻塞式調(diào)用,需要配置多一些進(jìn)程
worker_processes 1;
events {
worker_connections 1024;
}
http {
# 內(nèi)網(wǎng)地址
resolver xxx.x.x.xxx yyy.y.y.yyy;
# 日志格式配置
log_format graylog2_format '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'<msec=$msec|connection=$connection|connection_requests=$connection_requests|millis=$request_time>';
# 日志路徑配置
access_log syslog:server=<host>:<port> graylog2_format;
error_log syslog:server=<host>:<port> warn;
# 配置 Lua 包地址
lua_package_path '$prefix/lua/?.lua;;';
init_by_lua_block {
# 引入依賴(可能會(huì)污染全局環(huán)境,待研究)
http = require "resty.http"
cjson = require "cjson"
cache_management = require "cache_management"
...
}
# 設(shè)置定時(shí)任務(wù)緩存配置,及上面的 cache_management 模塊
init_worker_by_lua_file lua/init_work_by_lua.lua;
# Nginx Web 服務(wù)配置
server {
listen 80;
# ngx.location.capture 子請(qǐng)求代理,轉(zhuǎn)發(fā)原請(qǐng)求到接口服務(wù)
location = /ngx_proxy/ {
internal;
proxy_set_header Accept-Encoding '';
proxy_pass http://$context$http_host_suffix$proxy_uri;
}
# 匹配所有請(qǐng)求,進(jìn)行 URL 重寫、訪問控制、轉(zhuǎn)發(fā)請(qǐng)求以及響應(yīng)處理(各階段的處理在此配置)。
location / {
set $context '';
...
rewrite_by_lua_file lua/rewrite_by_lua.lua;
access_by_lua_file lua/access_by_lua.lua;
content_by_lua_file lua/content_by_lua.lua;
}
}
}
D. URL 規(guī)范
內(nèi)網(wǎng)服務(wù)遵循的 URL 格式為 http://<host>:<port>/<context>/path/to/your/api,應(yīng)用上下文根緊跟在 <host>:<port>之后,以便統(tǒng)一獲取來找到配置。比如:http://172.0.8.177:8080/user/users/{uid}/info,其中 user 為應(yīng)用上下文根,緊跟在 172.0.8.177:8080 之后。
E. 樣例
內(nèi)網(wǎng)用戶信息服務(wù)由原來的 API:/user/users/{uid}/info 提供,后來遷移至 API:/user/users/{uid}/user-info,當(dāng)?shù)谌?CampA (IP 為 172.0.1.172) 發(fā)起 GET 請(qǐng)求時(shí),請(qǐng)求 URL 為 http://openapi.company.com/user/users/27/info?thirdparty=CampA&cp=fj375x...sign=abxuos8nb...。
初始化常量和依賴等
通過 CampA 與 user Context 獲取第三方配置
HAProxy Internet 接收請(qǐng)求發(fā)到 OpenApi 接口網(wǎng)關(guān),OpenApi 把 /user/users/27/info URI 重寫為 /user/users/27/user-info/
校驗(yàn)第三方請(qǐng)求 IP,在 IP 白名單中,校驗(yàn)通過;校驗(yàn) URI /user/users/27/user-info 在授權(quán)的 URI 中,校驗(yàn)通過
調(diào)用安全服務(wù)對(duì)請(qǐng)求進(jìn)行解密與驗(yàn)簽,解密成功,驗(yàn)簽通過,獲取明文
將擁有明文的請(qǐng)求轉(zhuǎn)發(fā)到開放接口服務(wù)
獲取響應(yīng),調(diào)用安全服務(wù)對(duì)響應(yīng)報(bào)文進(jìn)行簽名與加密,返回給第三方 CampA。
3.2.2.2 配置服務(wù)設(shè)計(jì)
A. 數(shù)據(jù)庫表設(shè)計(jì)
openapi_thirdparty_config
id third_party need_check_ip ips req_need_verify_sign resp_need_sign
1 CompA 1 172.0.25.187, 172.0.25.188 1 1
openapi_api_config
id third_party method url req_need_decrypt resp_need_encrypt
1 CompA GET /user/users/[^/]+/userinfo 1 1
openapi_api_mapping
id from_api to_api
1 GET /old/1/user/users/(.+)/userinfo GET /users/$1/userinfo
B. 配置服務(wù)接口響應(yīng)
{
# 接口映射配置
"apiMapping":{
"$context":{
"$fromApi":"$toApi"
}
},
# 接口白名單配置、加解密配置
"apiConfig":{
"$channel $context":{
"$httpMethod $uri":{
"reqNeedDecrypt":false,
"respNeedEncrypt":false
}
}
},
# IP 白名單配置,驗(yàn)簽名配置
"channelConfig":{
"$channel":{
ips:{
"$ip":1
},
"reqNeedVerifySign":false,
"respNeedSign":false,
"needCheckIp":false
}
}
}
3.2.2.3 安全服務(wù)設(shè)計(jì)
為了保證請(qǐng)求或響應(yīng)的完整性、以及請(qǐng)求或響應(yīng)來源的合法性,雙方傳輸需要進(jìn)行簽名;另外,由于可能開放接口的請(qǐng)求或響應(yīng)會(huì)包含敏感信息,需要進(jìn)行加密傳輸。這里的安全服務(wù)就是指請(qǐng)求的解密與驗(yàn)簽和響應(yīng)的簽名與加密服務(wù)。
A. 算法約定
對(duì)稱加密算法:3DES(DESede/ECB/PKCS5Padding)
非對(duì)稱加密算法:RSA(RSA/ECB/PKCS1Padding)
簽名算法:SHA1WithRSA
B. 公鑰約定
雙方預(yù)先交換 RSA 公鑰
雙方公鑰編碼方式:UTF-8 編碼的 Base64String
雙方進(jìn)行加解密與驗(yàn)簽名可使用同一把 RSA 公私鑰或者分別使用各自的公私鑰,雙方約定即可
C. 第三方請(qǐng)求流程示意
其中,添加統(tǒng)一參數(shù)為必選步驟,請(qǐng)求簽名、請(qǐng)求加密、響應(yīng)解密、以及響應(yīng)驗(yàn)簽都是可選步驟。
無論是 GET、POST 或者其他方式的請(qǐng)求,第三方在訪問平臺(tái)開放接口前,都需要添加統(tǒng)一參數(shù)到 request parameter 中
統(tǒng)一參數(shù)包括第三方應(yīng)用名、請(qǐng)求時(shí)間戳、隨機(jī)不重復(fù)字符串 nonce 等
驗(yàn)簽名屬于應(yīng)用維度 —— 針對(duì)應(yīng)用做驗(yàn)簽名(比如:按照約定需要對(duì)第三方應(yīng)用 A 進(jìn)行驗(yàn)簽,則應(yīng)用 A 訪問平臺(tái)任何接口都需要簽名)
加解密屬于接口維度 —— 針對(duì)接口做加解密(比如:同一個(gè)第三方訪問 A 接口需要加密,而訪問 B 接口可以不需加密)
D. 加解密示意(以第三方請(qǐng)求為例)
E. 驗(yàn)簽名示意(以第三方請(qǐng)求為例)
3.2.3 架構(gòu)總結(jié)
由于 Nginx 與 Lua 本身杰出的性能,在當(dāng)前的系統(tǒng)量級(jí)與整體 IT 架構(gòu)下,我們使用這樣的接口網(wǎng)關(guān)架構(gòu)已經(jīng)可以支撐較大的并發(fā)請(qǐng)求。在最后的這一節(jié),我們不妨回顧一下前文講述的接口網(wǎng)關(guān)架構(gòu),看看目前性能上仍存在著的兩個(gè)主要待改進(jìn)的地方。
兩層 HAProxy 代理:在使用更優(yōu)產(chǎn)品替代 Openshift 架構(gòu)的情況下,直接部署接口網(wǎng)關(guān)到公網(wǎng),可消除外層 HAProxy 代理;在實(shí)現(xiàn)服務(wù)治理的情況下,由接口網(wǎng)關(guān)直接轉(zhuǎn)發(fā)請(qǐng)求到服務(wù),可消除內(nèi)層 HAProxy 代理。
安全服務(wù)性能:加解密驗(yàn)簽名等安全服務(wù)是以內(nèi)部服務(wù)的方式提供給接口網(wǎng)關(guān),而且使用了性能不太好的 ngx.location.capture 轉(zhuǎn)發(fā)原請(qǐng)求,在系統(tǒng)量級(jí)增大后會(huì)遇到性能瓶頸,可通過使用高性能的 Lua 腳本在接口網(wǎng)關(guān)層提供安全服務(wù),從而提升安全服務(wù)性能。
除了以上主要的兩點(diǎn),隨著系統(tǒng)量級(jí)的提升與整體 IT 架構(gòu)的演進(jìn),接口網(wǎng)關(guān)的架構(gòu)也會(huì)隨之調(diào)整和演進(jìn),在各個(gè)方面都盡可能地優(yōu)化性能,以適應(yīng)更大系統(tǒng)量級(jí)的需求。