Kong 網關使用入門

Kong介紹

Kong是一款基於Nginx_Lua模塊寫的高可用網關API,經過前置的負載均衡配置把請求均勻地分發到各個Server,來應對大批量的網絡請求。基於Nginx 特性,Kong自己也很是容易地擴展到多個服務器上。java

Kong主要有三個組件:nginx

Kong Server :基於nginx的服務器,用來接收API請求。
Apache Cassandra/PostgreSQL :用來存儲操做數據。
Kong dashboard:官方推薦UI管理工具,也可使用 restfull 方式 管理admin api。
複製代碼

Kong 工做方式web

Kong基本概念:sql

客戶端:指下游客戶向Kong的代理端口發出請求。
服務:服務實體,是對本身的每一個上游服務的抽象。客戶請求被轉發到該服務。
路由:路由是進入Kong的入口點,併爲要匹配的請求定義規則,並路由到給定的Service。服務和路由之間的關係是一對多的關係。
插件:它是在代理生命週期中運行的業務邏輯。能夠經過ADMIN API配置插件 - 全局(全部傳入流量)或特定的路由和服務。
用戶:是調用API 服務時身份認證的憑據
複製代碼

更多內容參考官網 konghq.com/kong/docker

安裝配置

本次基於docker 的方式進行安裝。Docker的安裝請參照 Docker實踐一 Docker安裝數據庫

一、在Docker中創建虛擬的網絡:

docker network create kong-net
複製代碼

後續的應用及數據庫都使用這個虛擬網絡。json

二、編寫docker-compose.yaml

version: "3.7"
services: 
  kong:
    # 鏡像版本,目前最新
    image: kong:1.1.2
    environment:
    # 數據持久化方式,使用postgres數據庫
     - "KONG_DATABASE=postgres"
    # 數據庫容器名稱,Kong鏈接數據時使用些名稱
     - "KONG_PG_HOST=kong-database"
    # 數據庫名稱
     - "KONG_CASSANDRA_CONTACT_POINTS=kong-database"
    # 日誌記錄目錄
     - "KONG_PROXY_ACCESS_LOG=/dev/stdout"
     - "KONG_ADMIN_ACCESS_LOG=/dev/stdout"
     - "KONG_PROXY_ERROR_LOG=/dev/stderr"
     - "KONG_ADMIN_ERROR_LOG=/dev/stderr"
    # 暴露的端口
     - "KONG_ADMIN_LISTEN=0.0.0.0:8001, 0.0.0.0:8444 ssl"
    ports:
     - 8000:8000
     - 8443:8443
     - 8001:8001
     - 8444:8444
    # 使用docker網絡
    networks:
     - kong-net
 
    # 依賴數據庫服務
    depends_on:
      - kong-database
# kong 管理界面
  konga:
    image: pantsel/konga
    environment:
     - "TOKEN_SECRET=51liveup.cn"
     - "NODE_ENV=production"
    ports:
     - 8080:1337
    networks:
     - kong-net
 
    depends_on:
      - kong-database
      - 
# 數據庫服務
  kong-database:
    image: postgres:9.6
    ports:
      - "5432:5432"
    environment:
    # 訪問數據庫的用戶
      - POSTGRES_USER=kong
      - POSTGRES_DB=kong
    networks:
      - kong-net
    volumes:
    # 同步時間
      - /etc/localtime:/etc/localtime:ro
    # 數據庫持久化目錄
      - /data/data/postgresql:/var/lib/postgresql/data
 
networks:
  kong-net:
    external: true
複製代碼

使用docker-compose up 命令啓動服務。會發現啓動時報數據庫錯誤,這是由於kong 使用的postgres 數據還須要進行初始化才能使用。bootstrap

三、初始化數據庫

docker run --rm \
     --network=kong-net \
     -e "KONG_DATABASE=postgres" \
     -e "KONG_PG_HOST=kong-database" \
     -e "KONG_CASSANDRA_CONTACT_POINTS=kong-database" \
     kong:latest kong migrations bootstrap

複製代碼

必定要在建立數據庫容器以後,而且保持數據庫的Docker容器在運行狀態,再執行初始化數據庫,數據庫初始化成功後,再次使用docker-compose up -d 啓動服務就能夠了。後端

驗證安裝

在宿主機上執行api

curl -i http://localhost:8001/

複製代碼

返回下面內容:

HTTP/1.1 200 OK
Date: Mon, 17 Jun 2019 02:43:33 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
Access-Control-Allow-Origin: *
Server: kong/1.1.2
Content-Length: 5860
 
 
....
複製代碼

表示安裝正確。能夠正常使用Kong了。

訪問 http://localhost:8080 訪問Konga 的管理界面,第一次登陸使用須要建立管理員賬號和密碼。

更多內容參照官網的安裝文檔

配置一個實例

配置一個訪問 www.baidu.com/ 的接口API,實際使用時會對接後端的業務數據接口地址。

一、建立服務

服務是上游服務的抽象,能夠是一個應用,或者具體某個接口。

命令行方式建立服務:

curl -i -X POST \
--url http://51liveup.cn:8001/services/ \
--data 'name=baidu-service' \
--data 'url=https://www.baidu.com/'
複製代碼

Konga 的管理界面建立和查看服務以下圖

二、建立路由

在剛纔建立的baidu-service的服務上建立路由

curl -i -X POST \
--url http://51liveup.cn:8001/services/baidu-service/routes \
--data 'hosts[]=baidu.com' \
--data 'paths[]=/api/baidu'
複製代碼

三、經過Postman 訪問數據

注意,若是Api暴露的地址與前面Host定義的地址(baidu.com)不一致,就須要在請求的Headers裏面加入參數Host=baidu.com

JWT 插件的使用

上面的配置,只要知道Router的地址,就能夠訪問獲取數據,咱們要把API加入身份認證。若是API面對不是具體用戶,而是其餘的系統,可使用JWT來進行系統間身份認證,使用Kong JWT插件就可能完成這功能。JWT 插件要在對應的Router上進行啓用。

curl -X POST http://51liveup.cn:8001/routes/fee36521-e549-410f-8986-9fbba02219c1/plugins \
    --data "name=jwt"
複製代碼

fee36521-e549-410f-8986-9fbba02219c1 是建立的router的ID。

這時再經過Postman 訪問上面的接口就會提示:

{
    "message": "Unauthorized"
}
複製代碼

客戶端要訪問須要提供JWT的認證信息才能夠。

建立用戶

curl -i -X POST \
--url http://51liveup.cn:8001/consumers/  \
--data "username=baiduuser"
複製代碼

用戶生成JWT憑證

curl -i -X POST \
--url http://51liveup.cn:8001/consumers/baiduuser/jwt \
--header "Content-Type: application/x-www-form-urlencoded"
複製代碼

返回憑證信息,也能夠經過 get 方法查詢憑證信息

{
    "rsa_public_key": null,
    "created_at": 1560723665,
    "consumer": {
        "id": "8bb94f49-22a6-4d77-9a64-21f13adc0342"
    },
    "id": "a110d234-6dc1-4443-9da2-21acddc66e09",
    "algorithm": "HS256",
    "secret": "lCe8Lbb7F0KtLccaBcBnOvYg76V7wmQx",
    "key": "7yQoUdF0aFUC9N593uLQLbqL7RSPj2qM"
}
複製代碼

使用key和secret在 jwt.io/ 能夠生成jwt 憑證信息.

再經過postman 訪問,就能夠看到數據了。

下面是經過Java代碼訪問數據的例子,不適用上面配置的baidu的接口。

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import okhttp3.*;
 
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Base64;
 
public class Example {
 
    public static void main(String[] args) {
        Example example = new Example();
        example.get("http://51liveup.cn:8000/api/xxxx/1");
    }
 
    public void get(String url) {
        OkHttpClient mOkHttpClient = new OkHttpClient();
        Request request = createBuilder().url(url).post(FormBody.create(MediaType.parse("application/json; charset=utf-8"), "{}")).build();
        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                System.out.println("failure : \r\n" + e);
            }
 
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                System.out.println("response:");
                System.out.println(response.body().string());
            }
        });
    }
 
    private Request.Builder createBuilder() {
        Request.Builder builder = new Request.Builder();
        builder.addHeader("host", "51liveup.cn");
        builder.addHeader("Authorization", "Bearer " + generateJwt());
        return builder;
    }
 
    private String generateJwt() {
        String jwt = Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")
                .setIssuer("7yQoUdF0aFUC9N593uLQLbqL7RSPj2qM")  // key
                .signWith(SignatureAlgorithm.HS256, Base64.getEncoder().encodeToString("lCe8Lbb7F0KtLccaBcBnOvYg76V7wmQx".getBytes(Charset.forName("utf-8"))))
                .compact();
        System.out.println("jwt:" + jwt);
        return jwt;
    }
}
複製代碼

ACL 插件的使用

JWT插件能夠保護API可以被受信用戶訪問,但不能區別哪一個用戶可以訪問哪一個API,即接口權限問題,咱們使用ACL 插件解決這個問題.

在上面定義好的路由上啓用acl 插件,指定白名單,

curl -i -X POST \
--url http://51liveup.cn:8001/routes/afb8bfbd-977e-464f-8c94-05d6c5c98429/plugins \
--data "name=acl"  \
--data "config.whitelist=baiduGroup"
複製代碼

此時再訪問api,會提示不能訪問這個服務。

{
    "message": "You cannot consume this service"
}
複製代碼

只需將baiduuser這個用戶關聯到白名單內的baiduGroup組裏便可。

curl -i -X POST \
--url http://localhost:8001/consumers/tianqiuser/acls \
--data "group=tianqi"
複製代碼

再次訪問接口,能正常返回數據。

如今就能夠對網關暴露的接口進行身份認證和權限控制了。

相關文章
相關標籤/搜索