使用Kong來管理業務側restful api

使用Kong來管理業務側restful api

導言

Kong是一個集成了Nginx的工具,除了具有正向/反向代理的功能以外,其還能擴展業務側API,爲業務側API加入認證,流控和管理等功能。Kong能夠充當任何HTTP資源的門戶,做爲代理服務器或網關,同時經過插件提供了日誌記錄,身份認證,流量控制等功能。html

建議已提早了解過如下技術點和知識

1,正向代理和反向代理的概念
2,Linux系列的系統的命令及其簡單操做
3,Nginx的簡單運用
4,Lua語言簡單語法 
5,CA--證書認證機構
6,restful API的特色
7,Http 基本認證
8,PostgreSQL的簡單使用
9,OpenSSL,https協議與http協議的聯繫,區別nginx

1、以Ubuntu Linux 爲例子,安裝Kong

(1)打開Kong的官網:docker

https://getkong.org/數據庫

點擊「Quick Start」,開始進入安裝簡介頁面。

能夠看出,目前Kong可以安裝在Linux陣營的系統或者docker等容器內。因此本文檔就以UBUNTU爲例,講述Kong的安裝特別是Kong的使用和管理Api等內容。ubuntu

(2)在安裝簡介頁面點擊你想安裝在哪種系統或容器中,本文檔已ubuntu爲例,進行安裝:點擊Ubuntu圖標,進入一個安裝包下載頁面,選擇好本身Ubuntu系統的版本號對應的安裝包下載便可。 api

(3)對下載好的安裝包,進行安裝,能夠參考官方提供的如下3句命令:服務器

$ sudo apt-get update  
$ sudo apt-get install netcat openssl libpcre3 dnsmasq procps perl  
$ sudo dpkg -i kong-0.9.3.*.deb

(4)因爲Kong做爲一個工具,有部分本身的信息須要數據庫進行存儲,這樣才能正常進行,而目前Kong支持的數據庫官方給出的內容是:「Kong supports both PostgreSQL 9.4+ and Cassandra 2.2.x 」,即至少要安裝PostgreSQL或者Cassandra兩種數據庫的其中一種。本文檔以PostgreSQL爲例子,與Kong進行配置集成。PostgreSQL具體能夠參考:restful

http://www.cnblogs.com/sparkdev/p/5678874.html架構

(5)安裝好PostgreSQL後,須要爲Kong建立一個數據庫而且須要一個名字爲kong的數據庫管理員。使用PostgreSQL建立用戶和數據庫,能夠參考下面的代碼:app

CREATE USER kong; CREATE DATABASE kong OWNER kong;

(6)創建好帳號後,須要對Kong進行數據庫配置。找到Kong的配置文件kong.conf ,進行鏈接項修改:
 
(7)前面的步驟若是完成了,不出意外,就能夠啓動Kong了。命令:

sudo kong start --conf /etc/kong/kong.conf

2、將本身的Restful Api加入到Kong中,進行管理

(1)首先,要將本身的restful api服務部署好並啓動。例如,咱們在172.31.31.128機器上面部署了一套restful API,以下圖所示。這套api將做爲咱們要加入到kong中的一個demo

(2)查閱Kong的5分鐘快速啓動指南,或者Kong自身的API文檔,準備好使用kong的自身API對本身業務側的restful API的管控。參考文檔的地址以下: 
《Kong-快速加入你的API》: https://getkong.org/docs/0.9.x/getting-started/adding-your-api/
《Kong-Add API》: https://getkong.org/docs/0.9.x/admin-api/#add-api

由文檔中,能夠看出,該kong自身的Api中,Post方法的/apis/地址接口,對應的是增長一個(一組)業務側的api。在列出的6個參數中,其中有幾個重要的參數:name,requestpath, upstreamurl
(3)若是Kong成功啓動了,那麼使用Kong自身的API的話,默認是8001端口。例如上面所說的Kong自身的Post /apis/ 接口,Kong部署到192.168.26.128,則使用它的時候,url爲: http://192.168.26.128:8001/apis/ 或者 http://localhost:8001/apis/。
(4)將以前已經部署好的業務側的API加入到Kong中:
命令:

curl -i -X POST --url http://localhost:8001/apis/ --data 'name=message_api' --data 'upstream_url=https://172.31.31.128:8183/' --data 'request_path=/'

這裏的upstreamurl 即上游地址,指向以前部署好的業務側接口API,其中"requestpath=/"表明的是該部署好的服務器下的全部API都被放入kong中受控。name=message_api該參數時給Kong自身的API使用的,至關於一個id。例如調用刪除接口或者認證接口的時候須要在url中指定該值做爲參數,讓Kong一一對應找到它所包含的業務側API進行相關操做。這樣,就至關於kong已經代理好了咱們以前在172.31.31.128部署好的業務側的API。 
(5)經過Kong的反向代理,對業務側的API進行訪問。這個時候,咱們只須要在url中填寫Kong服務器所在的地址便可:

 
由上圖能夠看出,咱們此次url上面的地址是kong的服務器IP地址192.168.26.128 。但實際上訪問它的時候,已經能夠去到部署到172.31.31.128的業務側API。這是由於Kong作了反向代理。API的調用方客戶能夠徹底不知道經歷了這一個過程。

3、將接入到Kong中的業務側API加上認證管理

(1)使用Kong自帶的「key-auth」插件對剛纔加入的業務側API進行認證受控。 命令:

curl -i -X POST --url http://localhost:8001/apis/message_api/plugins --data 'name=key-auth'


這個時候若是再次訪問上面例子中的GET /users接口的話,就會被禁止,而且提示401說未認證訪問的提示。

(2)同步業務側的認證數據到kong,讓kong去進行api的認證工做。例如業務側的數據庫有appKey和appSecret兩個fields做爲合法性認證的值。則能夠參考使用下面的語句進行同步到kong的配置信息數據庫PostgreSQL中:
命令:

curl -i -X POST --url http://localhost:8001/consumers/ --data "username=APPKEY_01"
curl -i -X POST --url http://localhost:8001/consumers/APPKEY_01/key-auth/ --data 'key=BASE64_APPKEY_01_APPSECRET_01'

我這裏只是用了APPKEY01,APPSECRET01這樣指代的值,實際操做中,應該填入真實的數據庫值信息。而且BASE64_APPKEY01APPSECRET01是指代使用Base64或者其加密的方法獲得的一種密文。
(3)對於受控的業務側API的訪問,須要在請求的Header中加入apiKey的參數和以前已經同步給Kong的密文。例以下面這樣,填入後,就能夠訪問了:

4、Kong目前版本及其插件,還不能知足咱們Api的一些需求

(1)上面第三節中,咱們已經把部署在172.31.31.128服務器的業務側restful API加入到Kong進行接口的身份認證,這也是咱們想要的效果。但同時,這樣也意味着,對於這一套業務側的API的每個接口,調用方的客戶在調用的時候都須要在請求的Header中加入apiKey的參數和以前已經同步給Kong。身份認證經過了,纔可以真正訪問獲得API並返回數據。例如咱們的業務側的API有如下這樣的一些典型的restful風格的API:

像這列表中的一系列的接口,都會被加入到Kong中,經過身份認證後才能訪問。
(2)有時候,一些系統中,總會有一些不須要認證就能夠直接使用的接口,例如一些系統的註冊接口等,由於用戶尚未註冊,即尚未本身的帳號,因此是不須要進行身份認證的。restful 風格的API有一個顯著的特色就是,請求的方法不一樣,表明的接口也是不一樣的。例如 POST /applications 接口與GET /applications 接口,雖然表面看url是同樣的,但實際上倒是兩個接口。
目前Kong的版本好似只有對一個URL地址下的API進行認證,即只達到路徑這一粒度的,尚未作到路徑上面還區分不一樣的方法例如POST、DELETE、GET等區別對待的認證,即「路徑+方法」這一粒度的。
例如:

這樣的典型restful api中,目前全部的接口都已經在kong中作了認證受控。但若是對於applications資源,我只但願POST方法這一條api進行特別處理,即不須要認證受控,則目前Kong以及它自帶的插好似作不了。

5、使用Lua開發本身的Kong插件,過濾請求的Http協議動詞

Kong做爲一個開源產品,有一個很是吸引人的地方就是能夠自由使用插件,而且還能夠是使用本身寫的插件,知足特定的業務需求。只要使用Lua語音,編寫好邏輯,創建好符合Kong規範的lua文件架構,Kong就能夠自動裝載和識別這些控件,給須要的Api使用。
(1)Kong插件的文件架構
最簡單的Kong插件開發,只須要完成handler.lua 和 schema.lua 這兩個文件的編碼便可。
其中handler.lua文件用於存放插件的須要完成的特定邏輯,而schema.lua至關於配置文件,用於存儲一些handler.lua中可能須要用到的可配置變量的值。
(2)Kong的插件通常存放在如下系統目錄下(以Ubuntu系統爲例):/usr/local/share/lua/5.1/kong/plugins/ ,咱們使用目錄列表語句,能夠查閱到該文件夾下到底有哪些Kong的插件:
 
Kong有自動檢查插件的機制,只要咱們在這個路徑下,新建一個有必定含義來命名的文件夾,並將handler.lua 和 schema.lua放入該文件夾內,則Kong就會自動掃描到並添加這一個插件,並且插件的名稱就是該文件夾的名稱。例如該路徑下有一個命名爲「key-auth」的文件夾,其就是以前咱們所用到的「key-auth」插件。
(3)仿造「key-auth」插件,改寫爲知足本身需求的新插件。 Kong做爲一個開源產品,它的內部的插件也是開放源代碼的。咱們能夠直接查閱它們的邏輯代碼甚至改寫。首先,咱們能夠在Kong的插件路徑下,新建一個「new-key-auth」的文件夾,而後將key-auth插件的全部的源碼文件都copy到該文件夾下。

參考命令:

sudo mkdir new-key-auth 
sudo cp -a ./key-auth/* ./new-key-auth

因爲key-auth插件只作到了路徑這一級粒度的認證,沒有作到路徑+Http方法這一級粒度的認證,全部,咱們就參考模仿它,而後把Http方法加上去!
首先在schema.lua中新增一些關於不須要認證的Http方法的配置: 參考代碼:

local function default_key_names(t)
  if not t.key_names then
    return {"apikey"}
  end
end

-- new default value function
local function default_not_need_auth_http_methods(t)
  if not t.not_need_auth_http_methods then
    return {"POST"}
  end
end

return {
  no_consumer = true,
  fields = {
    key_names = {required = true, type = "array", default = default_key_names},
    hide_credentials = {type = "boolean", default = false},
    -- new field
    not_need_auth_http_methods = {required = true, type = "array", default = default_not_need_auth_http_methods}
  }
}

這裏咱們新增了一個default_not_need_auth_http_methods(t)方法,以及一個not_need_auth_http_methods的配置。咱們這裏默認"POST"的Http方法不須要認證
接着,咱們在handler.lua中,找到function KeyAuthHandler:access(conf)這一方法,將這些配置加入到邏輯判斷中:
參考代碼:

function KeyAuthHandler:access(conf)
  KeyAuthHandler.super.access(self)

  local request_method = string.upper(ngx.req.get_method())
  local need_auth_flag = true


  for k, val in ipairs(conf.not_need_auth_http_methods) do
      if string.upper(val) == request_method then 
          need_auth_flag = false
      end
  end

  if need_auth_flag == true then
    if type(conf.key_names) ~= "table" then
      ngx.log(ngx.ERR, "[key-auth] no conf.key_names set, aborting plugin execution")
      return
    end

    .......

    set_header(constants.HEADERS.CONSUMER_ID, consumer.id)
    set_header(constants.HEADERS.CONSUMER_CUSTOM_ID, consumer.custom_id)
    set_header(constants.HEADERS.CONSUMER_USERNAME, consumer.username)
    ngx.ctx.authenticated_credential = credential
    ngx.ctx.authenticated_consumer = consumer
  end
end

return KeyAuthHandler

這裏有一行代碼是 local requestmethod = string.upper(ngx.req.getmethod()) 其中ngx.req.getmethod() 這一方法是使用了lua-nginx-module API 的函數,能獲取到該次請求的Http動詞方法。而後拿這一方法的值與配置的值想比較,看看是否須要身份認證才能往下執行業務側的API。
保存好handler.lua 和 schema.lua這兩個文件,去kong的配置文件中,找到custom
plugins一欄,將該控件設爲可用:

而後咱們爲以前方法爲http POST時候不須要認證的Api加入該新的插件:
參考代碼:

curl -i -X DELETE --url http://localhost:8001/apis/message_not_need_auth_api  
curl -i -X POST --url http://localhost:8001/apis/ --data 'name=message_applications_api' --data 'upstream_url=https://172.31.31.128:8183/' --data 'request_path=/applications'  
curl -i -X POST --url http://localhost:8001/apis/message_applications_api/plugins --data 'name=new-key-auth'

這樣,咱們就爲/applications 這一路徑的restful Api加入了本身的認證邏輯,即POST /applications 這一註冊應用的接口不須要身份認證,其餘的例如DELETE /applications 等接口,須要進行身份認證。

6、使用Kong自帶的插件進行Api請求的流控管理

許多須要對外開放的Api,都須要進行流控設置。Kong提供的插件中,就有這樣的幫助restful Api進行流控功能的插件。kong的流控插件有分爲調用次數限制的Rate Limiting插件和請求流量限制的Request Size Limiting插件。這裏咱們介紹調用次數限制的Rate Limiting插件。
(1)Rate Limiting插件簡介
Rate Limiting是對Http請求的次數,按照年,月,日,時,分,秒的粒度進行設置,能夠設置多個粒度,但至少要設置一個。例如,咱們能夠爲一個API設置每分鐘最多累計調用100次,每小時最多累計調用1000次,這樣就須要設置config.minute=100 和 config.hour=1000。若是用戶們1分鐘內調用超過100次的時候,Kong則會返回Http 429調用過快的狀態碼,須要下一分鐘才能調用。若是1小時累計超過1000次,則須要等待到下一小時(以該次調用的前999次的調用的時間差爲準)

(2)爲本身業務側的restful Api加入Rate Limiting插件 選擇須要進行流控限制的restful Api組,例如/applications,將其加上Rate Limiting插件。例如限制每分鐘5000次調用:
參考命令:

curl -i -X POST --url http://localhost:8001/apis/message_applications_api/plugins/ --data "name=rate-limiting" --data "config.minute=5000"

Kong的api返回相似下面這樣的提示,則表示成功:

當請求api的次數過快的時候,Kong會返回HTTP 429狀態碼提示:

@By_ljp_(PingLee)

(完)

相關文章
相關標籤/搜索