标签归档:Kong插件开发

微服务 API 网关 Kong 单元测试中文文档

原文链接: https://docs.konghq.com/1.0.x/plugin-development/tests/ (如有翻译的不准确或错误之处,欢迎留言指出)
集成测试:https://docs.konghq.com/1.0.x/plugin-development/tests/#write-integration-tests

介绍

如果你认真对待你写的插件,你可能想为它编写一些测试。Lua的单元测试很简单,并且可以使用许多测试框架。但是,您可能还想编写集成测试。Kong可以再次为您提供支援。

编写集成测试

Kong的首选测试框架是busted,它与resty-cli解释器一起运行,但如果您愿意,可以自由使用另一个。在Kong存储库中,可以在bin/busted找到 busted 的可执行文件。

Kong为您提供了一个帮助程序,可以在测试套件中从Lua启动和停止它:spec.helpers。此助手还提供了在运行测试之前在数据存储区中插入fixtures的方法,以及删除,以及各种其他helper。

如果您在自己的存储库中编写插件,则需要复制以下文件,直到Kong测试框架发布:

  • bin/busted: 与resty-cli解释器一起运行的 busted 的可执行文件
  • spec/helpers.lua:Kong的helper函数 可以从busted中 启动/关闭kong
  • spec/kong_tests.conf:使用helpers模块运行的Kong实例的配置文件

假设您的LUA_PATH中有spec.helpers模块,您可以使用以下Lua代码来启动和停止Kong:

local helpers = require "spec.helpers"

for _, strategy in helpers.each_strategy() do
  describe("my plugin", function()

    local bp = helpers.get_db_utils(strategy)

    setup(function()
      local service = bp.services:insert {
        name = "test-service",
        host = "httpbin.org"
      }

      bp.routes:insert({
        hosts = { "test.com" },
        service = { id = service.id }
      })

      -- start Kong with your testing Kong configuration (defined in "spec.helpers")
      assert(helpers.start_kong( { plugins = "bundled,my-plugin" }))

      admin_client = helpers.admin_client()
    end)

    teardown(function()
      if admin_client then
        admin_client:close()
      endhttps://github.com/Kong/kong/tree/master/spec/03-plugins/09-key-auth

      helpers.stop_kong()
    end)

    before_each(function()
      proxy_client = helpers.proxy_client()
    end)

    after_each(function()
      if proxy_client then
        proxy_client:close()
      end
    end)

    describe("thing", function()
      it("should do thing", function()
        -- send requests through Kong
        local res = proxy_client:get("/get", {
          headers = {
            ["Host"] = "test.com"
          }
        })

        local body = assert.res_status(200, res)

        -- body is a string containing the response
      end)
    end)
  end)
end

提醒:通过test Kong配置文件,Kong运行在代理监听端口9000(HTTP),9443 (HTTPS)和端口9001上的Admin API。

如果想看一下真实的例子,可以来这里看一看 Key-Auth plugin specs

微服务 API 网关 Kong 命令行中文文档

原文链接: https://docs.konghq.com/1.0.x/cli/
(如有翻译的不准确或错误之处,欢迎留言指出)

介绍

提供的CLI(命令行界面Command Line Interface)允许启动,停止和管理Kong实例。CLI可以管理本地节点(如在当前计算机上)。

如果您还没有使用,我们建议您阅读配置参考

通用标志参数

所有命令都将一组特殊的可选标志作为参数:

  • --help:打印此命令的帮助信息
  • --v:启用详细模式
  • --vv:启用调试模式(很多输出)

可用命令

kong check

Usage: kong check <conf>

检查给定Kong配置文件的有效性。

<conf> (default /etc/kong/kong.conf) 配置文件

kong health

Usage: kong health [OPTIONS]

验证Kong 的服务组件是否正常运行

Options:
 -p,--prefix      (可选参数) Kong运行位置的前缀

kong migrations

Usage: kong migrations COMMAND [OPTIONS]

管理数据库迁移。

可用的命令如下:
  bootstrap                         引导数据库并运行全部迁移(初始化)。

  up                                运行新迁移。

  finish                            完成正在等待中的迁移命令,在执行`up`后。

  list                              列出已执行的迁移。

  reset                             重置数据库。

Options(可选):
 -y,--yes                           假设提示“yes”,并运行非交互模式

 -q,--quiet                         忽略所有输出

 -f,--force                         依旧执行迁移,即使数据库报告已经执行过了。

 --db-timeout     (default 60)      超时时间,以秒为单位,所有数据库操作通用(包括Cassandra的schema consensus)。

 --lock-timeout   (default 60)      超时时间,以秒为单位, 节点等待领导节点迁移完成。

 -c,--conf        (optional string) 配置文件。

kong prepare

此命令用来准备Kong前缀文件夹及其子文件夹和文件。

Usage: kong prepare [OPTIONS]

在配置的前缀目录中准备Kong前缀。这个命令可以用于从nginx二进制文件启动Kong而不使用`kong start`命令。

Example usage:
  kong migrations up
  kong prepare -p /usr/local/kong -c kong.conf
  nginx -p /usr/local/kong -c /usr/local/kong/nginx.conf

Options:
  -c,--conf       (optional string) 配置文件
  -p,--prefix     (optional string) 覆盖前缀目录
  --nginx-conf    (optional string) 自定义Nginx配置模板

kong quit

Usage: kong quit [OPTIONS]

优雅地退出一个正在运行的Kong节点(Nginx和其他节点)在给定的前缀目录中配置的服务。

此命令将会向Nginx发送SIGQUIT信号,表示全部请求将在关闭之前完成处理。
如果达到超时延迟,则该节点将被强制执行停止(SIGTERM)

Options:
 -p,--prefix      (optional string) kong正在运行的前缀
 -t,--timeout     (default 10) 强制停止前的超时

kong reload

Usage: kong reload [OPTIONS]

重新加载Kong节点(并启动其他已配置的服务)在给定的前缀目录中。

此命令将HUP信号发送到Nginx,它将生成workers(告知account配置变更),当他们处理完成当前的请求后就停止旧的。

Options:
  -c,--conf       (optional string) 配置文件
  -p,--prefix     (optional string) 覆盖前缀目录
  --nginx-conf    (optional string) 自定义Nginx配置模板

kong restart

Usage: kong restart [OPTIONS]

重新启动Kong节点(以及其他配置的服务,如Serf)在给定的前缀目录中。

这个命令相当于同时执行`kong stop`和`kong start`。

Options:
 -c,--conf        (optional string)   配置文件
 -p,--prefix      (optional string)   Kong运行的前缀
 --nginx-conf     (optional string)   自定义Nginx配置模板
 --run-migrations (optional boolean)  可选地在DB上运行迁移
 --db-timeout     (default 60)
 --lock-timeout   (default 60)

kong start

Usage: kong start [OPTIONS]

在配置中启动Kong(Nginx和其他配置的服务)。

Options:
 -c,--conf        (optional string)   配置文件。

 -p,--prefix      (optional string)   覆盖前缀目录。

 --nginx-conf     (optional string)   自定义Nginx配置模板。

 --run-migrations (optional boolean)  在开始之前运行迁移。

 --db-timeout     (default 60)      超时时间,以秒为单位,所有数据库操作通用(包括Cassandra的schema consensus)。

 --lock-timeout   (default 60)      超时时间,以秒为单位, 节点等待领导节点迁移完成。

kong stop

Usage: kong stop [OPTIONS]

停止给定的正在运行的Kong节点(Nginx和其他已配置的服务)在指定的前缀目录。

此命令将SIGTERM信号发送到Nginx。

Options:
 -p,--prefix      (optional string) Kong运行的前缀

kong version

Usage: kong version [OPTIONS]

打印kong的版本。
使用-a选项,将打印所有底层依赖项的版本。

Options:
 -a,--all         获取所有依赖项的版本

微服务 API 网关 Kong File Log 插件中文文档

原文链接: https://docs.konghq.com/hub/kong-inc/file-log
(如有翻译的不准确或错误之处,欢迎留言指出)

将请求和响应数据写入磁盘上的日志文件中。不建议在生产中使用此插件,在生产环境下,最好使用另一个日志插件,例如syslog。由于系统限制,此插件使用阻塞文件i/o,将会损害性能,因此是Kong安装的反面模式。
注意:此插件的功能与0.10.2之前的Kong版本捆绑在一起,与此处记录的不同。 有关详细信息,请参阅CHANGELOG

配置

在服务上启用插件

通过发出以下请求在服务上配置此插件:

$ curl -X POST http://kong:8001/services/{service}/plugins \
    --data "name=file-log"  \
    --data "config.path=/tmp/file.log"

service:此插件配置将绑定的服务的ID或名称。

在路由上启用插件

Route上配置此插件:

$ curl -X POST http://kong:8001/routes/{route_id}/plugins \
    --data "name=file-log"  \
    --data "config.path=/tmp/file.log"

route_id:此插件配置将绑定的路由的ID。

在Consumer上启用插件

您可以使用 http://localhost:8001/plugins 端点在特定的Consumers上启用此插件:

$ curl -X POST http://kong:8001/plugins \
    --data "name=file-log" \
    --data "consumer_id={consumer_id}"  \
    --data "config.path=/tmp/file.log"

其中,consumer_id是我们想要与此插件关联的消费者的ID。您可以组合consumer_idservice_id。在同一个请求中,进一步缩小插件的范围。

全局插件

可以使用http://kong:8001/plugins/ 配置所有插件。与任何服务,路由或消费者(或API,如果您使用旧版本的Kong)无关的插件被视为“全局”,并将在每个请求上运行。有关更多信息,请阅读插件参考插件优先级部分。

参数

以下是可在此插件配置中使用的所有参数的列表:

参数名称 默认值 描述
name 要使用的插件的名称,在本例中为file-log
service_id 此插件将关联的服务的ID。
route_id 此插件将关联的路由的ID。
enabled true 是否将应用此插件。
consumer_id 此插件将定位的绑定的id。
config.path 输出日志文件的文件路径。
如果该文件尚不存在,该插件将创建该文件。
确保Kong对此文件具有写入权限。
config.reopen false 在kong0.10.2引入。确定是否关闭日志文件并在每个请求时重新打开。 如果文件未重新打开,并且已被删除/循环,则插件将继续写入过时的文件描述符,从而丢失信息。

日志格式

每个请求将分别记录在由新行\n分隔的JSON对象中,格式如下:

{
    "request": {
        "method": "GET",
        "uri": "/get",
        "url": "http://httpbin.org:8000/get",
        "size": "75",
        "querystring": {},
        "headers": {
            "accept": "*/*",
            "host": "httpbin.org",
            "user-agent": "curl/7.37.1"
        }
    },
    "upstream_uri": "/",
    "response": {
        "status": 200,
        "size": "434",
        "headers": {
            "Content-Length": "197",
            "via": "kong/0.3.0",
            "Connection": "close",
            "access-control-allow-credentials": "true",
            "Content-Type": "application/json",
            "server": "nginx",
            "access-control-allow-origin": "*"
        }
    },
    "tries": [
        {
            "state": "next",
            "code": 502,
            "ip": "127.0.0.1",
            "port": 8000
        },
        {
            "ip": "127.0.0.1",
            "port": 8000
        }
    ],
    "authenticated_entity": {
        "consumer_id": "80f74eef-31b8-45d5-c525-ae532297ea8e",
        "id": "eaa330c0-4cff-47f5-c79e-b2e4f355207e"
    },
    "route": {
        "created_at": 1521555129,
        "hosts": null,
        "id": "75818c5f-202d-4b82-a553-6a46e7c9a19e",
        "methods": null,
        "paths": [
            "/example-path"
        ],
        "preserve_host": false,
        "protocols": [
            "http",
            "https"
        ],
        "regex_priority": 0,
        "service": {
            "id": "0590139e-7481-466c-bcdf-929adcaaf804"
        },
        "strip_path": true,
        "updated_at": 1521555129
    },
    "service": {
        "connect_timeout": 60000,
        "created_at": 1521554518,
        "host": "example.com",cuowu
        "id": "0590139e-7481-466c-bcdf-929adcaaf804",
        "name": "myservice",
        "path": "/",
        "port": 80,
        "protocol": "http",
        "read_timeout": 60000,
        "retries": 5,
        "updated_at": 1521554518,
        "write_timeout": 60000
    },
    "workspaces": [
        {
            "id":"b7cac81a-05dc-41f5-b6dc-b87e29b6c3a3",
            "name": "default"
        }
    ],
    "consumer": {
        "username": "demo",
        "created_at": 1491847011000,
        "id": "35b03bfc-7a5b-4a23-a594-aa350c585fa8"
    },
    "latencies": {
        "proxy": 1430,
        "kong": 9,
        "request": 1921
    },
    "client_ip": "127.0.0.1",
    "started_at": 1433209822425
}

关于上述JSON对象的一些注意事项:

  • request 包含有关客户端发送的请求的属性
  • response 包含有关发送到客户端的响应的属性
  • tries 包含负载均衡器为此请求进行的(重新)尝试(成功和失败)列表
  • route 包含有关所请求的特定路线的Kong属性
  • service 包含与所请求的路线相关联的服务的Kong属性
  • authenticated_entity 包含有关经过身份验证的凭据的Kong属性(如果已启用身份验证插件)
  • workspaces 包含与请求的路由关联的工作空间的Kong属性。仅限Kong Enterprise版本> = 0.34
  • consumer 包含经过身份验证的使用者(如果已启用身份验证插件)
  • latencies 包含一些有关延迟的数据:
    • proxy 是最终服务处理请求所花费的时间
    • kong 是运行所有插件所需的内部Kong延迟
    • request 是从客户端读取的第一个字节之间以及最后一个字节发送到客户端之间经过的时间。用于检测慢速客户端。
  • client_ip 包含原始客户端IP地址
  • started_at 包含开始处理请求的UTC时间戳。

Kong执行错误

此日志记录插件仅记录HTTP请求和响应数据。 如果您正在寻找Kong进程错误文件(这是nginx错误文件),那么您可以在以下路径找到它:{prefix}/logs/error.log

微服务 API 网关 Kong CORS 插件中文文档

原文地址:https://docs.konghq.com/hub/kong-inc/cors/ (不能保证所有的翻译都是准确无误的,所有如有翻译的不准确或错误之处,请一定记得查看原文,并欢迎留言指出)。

通过启用此插件,轻松将跨源资源共享(CORS)添加到 Service, Route 。

配置

在 Service 上启用插件

通过发出以下请求在 Service 上配置此插件:

$ curl -X POST http://kong:8001/services/{service}/plugins \
    --data "name=cors"  \
    --data "config.origins=http://mockbin.com" \
    --data "config.methods=GET, POST" \
    --data "config.headers=Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Auth-Token" \
    --data "config.exposed_headers=X-Auth-Token" \
    --data "config.credentials=true" \
    --data "config.max_age=3600"
  • service:此插件配置将绑定的服务的ID或名称。

在 Route 上启用插件

通过发出以下请求在 Route 上配置此插件:

$ curl -X POST http://kong:8001/routes/{route_id}/plugins \
    --data "name=cors"  \
    --data "config.origins=http://mockbin.com" \
    --data "config.methods=GET, POST" \
    --data "config.headers=Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Auth-Token" \
    --data "config.exposed_headers=X-Auth-Token" \
    --data "config.credentials=true" \
    --data "config.max_age=3600"

全局插件

可以使用http://kong:8001/plugins/ 配置所有插件。与任何Service, Route 或者 Consumer(或API,如果您使用旧版本的Kong)无关的插件被视为“全局”,并将在每个请求上运行。有关更多信息,请阅读插件参考插件优先级部分。

参数

以下是可在此插件配置中使用的所有参数的列表:

参数名称 默认值 描述
name 要使用的插件的名称,在本例中为cors
service_id 此插件将绑定的 Service 的ID。
route_id 此插件将绑定的 Route 的ID。
enabled true 是否将应用此插件。
config.origins 
optional
Access-Control-Allow-Origin标头的允许域,用逗号分割,如果想允许所有,就使用*。接受的值可以是flat strings 或PCRE正则表达式。 
注意:在Kong 0.10.x之前,此参数是config.origin(请注意s的更改),并且只接受单个值或*特殊值。
config.methods 
optional
GET, HEAD, PUT, PATCH,POST Access-Control-Allow-Methods header的值,使用逗号分隔的字符串(例如GETPOST)。
config.headers 
optional
Access-Control-Request-Headers请求header的值 Access-Control-Allow-Headers header的值,使用逗号分割(例如OriginAuthorization)。
config.exposed_headers 
optional
Access-Control-Expose-Headers header 的值,使用逗号分割(例如OriginAuthorization),如果未指定,则不会开放自定义header。
config.credentials 
optional
false 用于确定是否应使用true作为值发送Access-Control-Allow-Credentialsheader。
config.max_age 
optional
指示可以缓存预检请求的结果的时间长度(以秒为单位)。
config.preflight_continue
optional
false 一个布尔值,指示插件将OPTIONS预检请求代理到上游服务。

相关问题

以下是此插件的已知问题或限制的列表。

CORS限制

如果客户端是浏览器,则由于CORS规范的限制导致此插件存在已知问题,该限制不允许在预检OPTIONS请求中指定自定义header。
由于此限制,此插件仅适用于已使用路径设置配置的路由,并且对于使用自定义DNS(hosts属性)解析的路由不起作用。
要了解如何为Route配置路径,请阅读代理参考

微服务 API 网关 Kong 插件开发添加自定义配置文件

由于在 Kong 的插件开发中,需要添加一些自定义的配置文件,而且是一些插件公用的配置,但是又不方便都写在插件的 schema.lua 中,那么就考虑引入常规的配置文件,这里以.env文件为例,写一下添加和使用过程。

首先需要了解的是,Kong 的插件使用了一个叫 Classic 的 class 机制。所有的插件都是从 base_plugin.lua 基类上继承而来。base_plugin.lua 定义了插件在各个阶段被执行的方法名:,所以我们就从这里入手,以添加redis配置信息为例。

添加配置文件

进入到插件目录,我这里是/usr/local/share/lua/5.1/kong/plugins,然后新建一个.env文件,写入:

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=
REDIS_PORT=6379

添加获取配置文件内容方法

然后编辑base_plugin.lua,(需要注意的是,这里可能会有权限问题),在

return BasePlugin

这一行上加上获取.env的方法

-- 获取配置文件
function BasePlugin:load_ini()

    if config_data then
        return config_data
    end

    config_data = {}

    local info = debug.getinfo(1, "S")
    local path = info.source
    path = string.sub(path, 2, -1) -- 去掉开头的"@"
    path = string.match(path, "^.*/") -- 捕获最后一个 "/" 之前的部分 就是我们最终要的目录部分

    local conf, err = resty_ini.parse_file(path .. ".env")

    if not conf then
        ngx_log( ngx.ERR, "[ -- can not find file .env -- ]" .. tostring(err))
        return
    end

    for section, values in pairs(conf) do
        for k, v in pairs(values) do
            config_data[k] = v
        end
    end

    return config_data
end

把配置文件中的内容以键值对的形式放在一个名为config_data的table中。

使用配置内容

base_plugin.lua里加好了之后,回到自己的自定义插件开发中。获取配置文件内容如下:

local ini_conf = BasePlugin:load_ini()
if not ini_conf then
    ngx.log(ngx.ERR, "[ -- redis-log -- ] failed to read .env ", err)
end

使用配置文件的内容来链接并验证redis

function connectme()

    local red = redis:new()

    red:set_timeout(1000)

    if not ini_conf then
        ngx_log(ngx.ERR, "[ -- redis-log -- ] failed to read .env ", err)
    end

    local redis_host = ini_conf['REDIS_HOST']
    local redis_port = ini_conf['REDIS_PORT']
    local redis_password = ini_conf['REDIS_PASSWORD']

    local ok, err = red:connect(redis_host, redis_port)

    if not ok then
        ngx_log(ngx.ERR, "[ -- redis-log -- ] failed to connect to Redis: ", err)
        return
    end

    if redis_password then
        local ok, err = red:auth(redis_password)
        if not ok then
            ngx_log(ngx.ERR, "[ -- redis-log -- ] failed to auth to Redis: ", err)
            return
        end
    end

    return red
end

最后需要说明的是,每次修改了配置文件,需要重新加载一下整个插件,也就是可能需要重新启动一下kong。如果有更好更更合理的方法,欢迎留言~

微服务 API 网关 Kong 插件开发套件PDK 中文文档

原文地址:https://docs.konghq.com/1.0.x/pdk/(不能保证所有的翻译都是准确无误的,所有如有翻译的不准确或错误之处,请一定记得查看原文,并欢迎留言指出)。

插件开发工具包 Plugin Development Kit(或“PDK”)是一组Lua函数和变量,插件可以使用这些函数和变量来实现自己的逻辑。PDK是一个语义版本的组件,最初在Kong 0.14.0中发布。PDK将保证从1.0.0版本开始向前兼容。

截至本版本,PDK尚未达到1.0.0,但插件作者已经可以依赖它来使用安全可靠的方式进行请求、响应或者做一些核心组件。

可以从kong全局变量访问插件开发工具包,并在此表下命名各种功能,例如kong.requestkong.log等…

kong.version

一个可以直观阅读的字符串,包含当前正在运行的节点的版本号。

用法

print(kong.version) -- "0.14.0"
Back to TOC

kong.version_num

表示当前运行节点的版本号的整数,用于比较和特征存在检查。

用法

if kong.version_num < 13000 then -- 000.130.00 -> 0.13.0
  -- no support for Routes & Services
end

kong.pdk_major_version

表示当前PDK主要版本的数字(例如1)。 对于作为PDK用户的特征存在检查或向后兼容行为很有用。

用法

if kong.pdk_version_num < 2 then
  -- PDK is below version 2
end
Back to TOC

kong.pdk_version

一个可以直观阅读的字符串,包含当前PDK的版本号。

用法

print(kong.pdk_version) -- "1.0.0"

kong.configuration

包含当前Kong节点配置的只读表,基于配置文件和环境变量。 有关详细信息,请参阅kong.conf.default。 该文件中以逗号分隔的列表将被提升为此表中的字符串数组。

用法

print(kong.configuration.prefix) -- "/usr/local/kong"
-- this table is read-only; the following throws an error:
kong.configuration.prefix = "foo"

kong.db

Kong的DAO实例(kong.db模块)。 包含各种实体的访问者对象。

用法

kong.db.services:insert()
kong.db.routes:select()

将来可以提供有关此DAO和新模式定义的更全面的文档。

kong.dns

Kong的DNS解析器实例,来自lua-resty-dns-c模块的客户端对象。 注意:此模块的使用目前保留给核心或高级用户。

kong.worker_events

Kong的IPC模块实例,用于来自lua-resty-worker-events模块的员工间通信。 注意:此模块的使用目前保留给核心或高级用户。

kong.cluster_events

用于节点间通信的Kong的集群事件模块的实例。 注意:此模块的使用目前保留给核心或高级用户。 回到TOC

kong.cache

来自kong.cache模块的Kong数据库缓存对象的实例。 注意:此模块的使用目前保留给核心或高级用户。

微服务 API 网关 Kong Route 中文文档

原文地址:https://docs.konghq.com/1.0.x/admin-api/#route-object (不能保证所有的翻译都是准确无误的,所有如有翻译的不准确或错误之处,请一定记得查看原文,并欢迎留言指出)。

route 路由

路由实体定义规则以匹配客户端请求。每个Route与一个服务相关联,一个服务可能有多个与之关联的路由。匹配给定路由的每个请求都将代理到其关联的服务。
Routes 和 Services 的组合(以及它们之间的关注点分离)提供了一种强大的路由机制,通过它可以在 Kong 中定义细粒度的入口点,从而导致基础架构的不同上游服务。

{
    "id": "173a6cee-90d1-40a7-89cf-0329eca780a6",
    "created_at": 1422386534,
    "updated_at": 1422386534,
    "name": "my-route",
    "protocols": ["http", "https"],
    "methods": ["GET", "POST"],
    "hosts": ["example.com", "foo.test"],
    "paths": ["/foo", "/bar"],Service 服务
    "regex_priority": 0,
    "strip_path": true,
    "preserve_host": false,
    "service": {"id":"f5a9c0ca-bdbb-490f-8928-2ca95836239a"}
}

添加 route

创建一个route

POST:/routes

创建与特定服务关联的路由

POST:/services/{service name or id}/routes
参数 描述
service name or id 
required
应与新创建的路由关联的服务的唯一标识符或名称属性。

请求体

参数 描述
name 
optional
Route 名称
protocols 此路由应允许的协议列表。设置为[“https”]时,将通过请求升级到HTTPS来回答HTTP请求。默认为[“http”,“https”]
methods 
semi-optional
与此Route匹配的HTTP方法列表。使用http或https协议时,必须至少设置一个hosts, paths, or methods
hosts 
semi-optional
与此路由匹配的域名列表。使用httphttps协议时,必须至少设置一个hosts, paths, 或者 methods。使用表单编码时,符号是hosts [] = example.com&hosts [] = foo.test。使用JSON,使用Array。
paths 
semi-optional
与此路由匹配的路径列表。使用httphttps协议时,必须至少设置一个必须至少设置一个hosts, paths, 或者methods。使用表单编码时,符号是paths [] = / foo&paths [] = / bar。使用JSON,使用数组。
regex_priority
optional
用于选择哪条路由解析给定请求的数字,当多条路由同时使用正则表达式匹配时。当两条路径匹配路径并具有相同的regex_priority时,将使用较旧的路径(最低的created_at)。请注意,非正则表达式路由的优先级不同(较长的非正则表达式路由在较短的路由之前匹配)。默认为0
strip_path 
optional
通过其中一条path匹配Route时,从上游请求URL中删除匹配的前缀。默认为true
preserve_host 
optional
通过其中一个主机域名匹配Route时,请使用上游请求标头中的请求主机头。如果设置为false,则上游主机头将是服务主机的头。
snis 
semi-optional
使用流路由时与此路由匹配的SNI列表。使用tcptls协议时,必须至少设置一个snissourcesdestinations PUT
sources 
semi-optional
使用流路由时与此路由匹配的传入连接的IP源列表。每个条目都是一个对象,其字段为“ip”(可选地为CIDR范围表示法)和/或“port”。使用tcptls协议时,必须至少设置一个snissourcesdestinations
destinations 
semi-optional
使用流路由时,与此路由匹配的传入连接的IP目标列表。每个条目都是一个对象,其字段为“ip”(可选地为CIDR范围表示法)和/或“port”。使用tcptls协议时,必须至少设置一个snissourcesdestinations
service 此路由所关联的服务。这是Route代理流量的地方,使用表单encode。表示法是service.id = <service_id>。使用JSON,使用“service”:{“id”:“<service_id>”}

响应

HTTP 201 Created
{
    "id": "173a6cee-90d1-40a7-89cf-0329eca780a6",
    "created_at": 1422386534,
    "updated_at": 1422386534,
    "name": "my-route",
    "protocols": ["http", "https"],
    "methods": ["GET", "POST"],
    "hosts": ["example.com", "foo.test"],
    "paths": ["/foo", "/bar"],
    "regex_priority": 0,
    "strip_path": true,
    "preserve_host": false,
    "service": {"id":"f5a9c0ca-bdbb-490f-8928-2ca95836239a"}
}

路由列表

所有路由列表

GET:/routes

列出与特定服务关联的路由列表

GET:/services/{service name or id}/routes
参数 描述
service name or id 
required
要检索其路由的服务的唯一标识符或name属性。仅列出与指定服务关联的路由。

响应

HTTP 200 OK
{
"data": [{
    "id": "885a0392-ef1b-4de3-aacf-af3f1697ce2c",
    "created_at": 1422386534,
    "updated_at": 1422386534,
    "name": "my-route",
    "protocols": ["http", "https"],
    "methods": ["GET", "POST"],
    "hosts": ["example.com", "foo.test"],
    "paths": ["/foo", "/bar"],
    "regex_priority": 0,
    "strip_path": true,
    "preserve_host": false,
    "service": {"id":"a3395f66-2af6-4c79-bea2-1b6933764f80"}
}, {
    "id": "4fe14415-73d5-4f00-9fbc-c72a0fccfcb2",
    "created_at": 1422386534,
    "updated_at": 1422386534,
    "name": "my-route",
    "protocols": ["tcp", "tls"],
    "regex_priority": 0,
    "strip_path": true,
    "preserve_host": false,
    "snis": ["foo.test", "example.com"],
    "sources": [{"ip":"10.1.0.0/16", "port":1234}, {"ip":"10.2.2.2"}, {"port":9123}],
    "destinations": [{"ip":"10.1.0.0/16", "port":1234}, {"ip":"10.2.2.2"}, {"port":9123}],
    "service": {"id":"ea29aaa3-3b2d-488c-b90c-56df8e0dd8c6"}
}],

    "next": "http://localhost:8001/routes?offset=6378122c-a0a1-438d-a5c6-efabae9fb969"
}

查询路由

查询路由

GET:/routes/{name or id}
参数 描述
service name or id 
required
要检索其路由的服务的唯一标识符或name属性。仅列出与指定服务关联的路由。

查询与特定插件关联的路由

GET:/plugins/{plugin id}/route
参数 描述
plugin id 
required
与要更新的路由关联的插件的唯一标识符。

响应

HTTP 200 OK
{
    "id": "173a6cee-90d1-40a7-89cf-0329eca780a6",
    "created_at": 1422386534,
    "updated_at": 1422386534,
    "name": "my-route",
    "protocols": ["http", "https"],
    "methods": ["GET", "POST"],
    "hosts": ["example.com", "foo.test"],
    "paths": ["/foo", "/bar"],
    "regex_priority": 0,
    "strip_path": true,
    "preserve_host": false,
    "service": {"id":"f5a9c0ca-bdbb-490f-8928-2ca95836239a"}
}

PUT

更新路由

更新路由

PATCH:/routes/{name or id}
参数 描述
name or id 
required
唯一标识符或要更新的路由的名称。

更新与特定插件关联的路由

PATCH:/plugins/{plugin id}/route
参数 描述
plugin id 
required
与要更新的路由关联的插件的唯一标识符。

请求体

参数 描述
name 
optional
Route 名称
protocols 此路由应允许的协议列表。设置为[“https”]时,将通过请求升级到HTTPS来回答HTTP请求。默认为[“http”,“https”]
methods 
semi-optional
与此Route匹配的HTTP方法列表。使用http或https协议时,必须至少设置一个hosts, paths, or methods
hosts 
semi-optional
与此路由匹配的域名列表。使用httphttps协议时,必须至少设置一个hosts, paths, 或者 methods。使用表单编码时,符号是hosts [] = example.com&hosts [] = foo.test。使用JSON,使用Array。
paths 
semi-optional
与此路由匹配的路径列表。使用httphttps协议时,必须至少设置一个必须至少设置一个hosts, paths, 或者methods。使用表单编码时,符号是paths [] = / foo&paths [] = / bar。使用JSON,使用数组。
regex_priority
optional
用于选择哪条路由解析给定请求的数字,当多条路由同时使用正则表达式匹配时。当两条路径匹配路径并具有相同的regex_priority时,将使用较旧的路径(最低的created_at)。请注意,非正则表达式路由的优先级不同(较长的非正则表达式路由在较短的路由之前匹配)。默认为0
strip_path 
optional
通过其中一条path匹配Route时,从上游请求URL中删除匹配的前缀。默认为true
preserve_host 
optional
通过其中一个主机域名匹配Route时,请使用上游请求标头中的请求主机头。如果设置为false,则上游主机头将是服务主机的头。
snis 
semi-optional
使用流路由时与此路由匹配的SNI列表。使用tcptls协议时,必须至少设置一个snissourcesdestinations
sources 
semi-optional
使用流路由时与此路由匹配的传入连接的IP源列表。每个条目都是一个对象,其字段为“ip”(可选地为CIDR范围表示法)和/或“port”。使用tcptls协议时,必须至少设置一个snissourcesdestinations
destinations 
semi-optional
使用流路由时,与此路由匹配的传入连接的IP目标列表。每个条目都是一个对象,其字段为“ip”(可选地为CIDR范围表示法)和/或“port”。使用tcptls协议时,必须至少设置一个snissourcesdestinations
service 此路由所关联的服务。这是Route代理流量的地方,使用表单encode。表示法是service.id = <service_id>。使用JSON,使用“service”:{“id”:“<service_id>”}

响应

HTTP 200 OK
{
    "id": "173a6cee-90d1-40a7-89cf-0329eca780a6",
    "created_at": 1422386534,
    "updated_at": 1422386534,
    "name": "my-route",
    "protocols": ["http", "https"],
    "methods": ["GET", "POST"],
    "hosts": ["example.com", "foo.test"],
    "paths": ["/foo", "/bar"],
    "regex_priority": 0,
    "strip_path": true,
    "preserve_host": false,
    "service": {"id":"f5a9c0ca-bdbb-490f-8928-2ca95836239a"}
}
参数 描述
plugin id 
required
与要更新的路由关联的插件的唯一标识符。

更新或创建路由

更新或创建一个路由

PUT:/routes/{name or id}
| 参数 | 描述 |
| ---- | ---- |
| `name or id` <br> ** required ** | 要创建或更新的路由的唯一标识符或名称。 |

创建或更新与特定插件关联的路由

PUT:/plugins/{plugin id}/route
参数 描述
plugin id 
required
与要更新的路由关联的插件的唯一标识符。

请求体

参数 描述
name 
optional
Route 名称
protocols 此路由应允许的协议列表。设置为[“https”]时,将通过请求升级到HTTPS来回答HTTP请求。默认为[“http”,“https”]
methods 
semi-optional
与此Route匹配的HTTP方法列表。使用http或https协议时,必须至少设置一个hosts, paths, or methods
hosts 
semi-optional
与此路由匹配的域名列表。使用httphttps协议时,必须至少设置一个hosts, paths, 或者 methods。使用表单编码时,符号是hosts [] = example.com&hosts [] = foo.test。使用JSON,使用Array。
paths 
semi-optional
与此路由匹配的路径列表。使用httphttps协议时,必须至少设置一个必须至少设置一个hosts, paths, 或者methods。使用表单编码时,符号是paths [] = / foo&paths [] = / bar。使用JSON,使用数组。
regex_priority
optional
用于选择哪条路由解析给定请求的数字,当多条路由同时使用正则表达式匹配时。当两条路径匹配路径并具有相同的regex_priority时,将使用较旧的路径(最低的created_at)。请注意,非正则表达式路由的优先级不同(较长的非正则表达式路由在较短的路由之前匹配)。默认为0
strip_path 
optional
通过其中一条path匹配Route时,从上游请求URL中删除匹配的前缀。默认为true
preserve_host 
optional
通过其中一个主机域名匹配Route时,请使用上游请求标头中的请求主机头。如果设置为false,则上游主机头将是服务主机的头。
snis 
semi-optional
使用流路由时与此路由匹配的SNI列表。使用tcptls协议时,必须至少设置一个snissourcesdestinations
sources 
semi-optional
使用流路由时与此路由匹配的传入连接的IP源列表。每个条目都是一个对象,其字段为“ip”(可选地为CIDR范围表示法)和/或“port”。使用tcptls协议时,必须至少设置一个snissourcesdestinations
destinations 
semi-optional
使用流路由时,与此路由匹配的传入连接的IP目标列表。每个条目都是一个对象,其字段为“ip”(可选地为CIDR范围表示法)和/或“port”。使用tcptls协议时,必须至少设置一个snissourcesdestinations
service 此路由所关联的服务。这是Route代理流量的地方,使用表单encode。表示法是service.id = <service_id>。使用JSON,使用“service”:{“id”:“<service_id>”}

使用请求提中指定的参数插入(或替换)请求资源下的路由。Route将通过nameid属性进行标识。
nameid属性具有UUID的结构时,插入/替换的Route将由其id标识。否则将通过其name识别。
在创建新路由而不指定id(既不在URL中也不在主体中)时,它将自动生成。
请注意,不允许在URL中指定name,在请求正文中指定其他名称。

响应

HTTP 201 Created or HTTP 200 OK

参考 POST 和 PATCH 的响应。

删除路由

删除一个路由

DELETE:/routes/{name or id}
| 参数 | 描述 |
| ---- | ---- |
| `name or id` <br> ** required ** | 要删除的路由的唯一标识符或名称。 |

响应

HTTP 204 No Content

微服务 API 网关 Kong 1.0 GA 版本正式发布(更新详情)

原文地址:https://github.com/Kong/kong/blob/master/CHANGELOG.md#100 ,(如有翻译的不准确或错误之处,欢迎留言指出)

这个是一个非常重要的版本,引入了对Service Mesh和Stream Routing支持的新功能,以及新的迁移框架,它还包括插件开发工具包(Plugin Development Kit)的1.0.0版本,它包含大量其他功能和修复,如下所示。此外,Kong 1.0中包含的所有插件都更新为使用PDK 1.0版。

像往常一样,主要版本升级需要数据库迁移和Nginx配置文件的更改(如果您自定义了默认模板),在计划升级Kong集群之前,请花几分钟时间阅读1.0升级指南,了解有关更改和迁移的更多详细信息。

作为主要版本,在Kong 0.x中标记为已弃用的所有实体和概念现已在Kong 1.0中删除,已弃用的功能将保留在Kong 0.15中,Kong 0.x系列的最终版本,同时发布到Kong 1.0。

重大更新

Kong 1.0包括0.15的所有重大更改,以及删除已弃用的概念:

核心:

  • API实体和相关概念( 例如/apis )将被删除(自0.13版本,2018年三月起不推荐使用)。请改用路由和服务。
  • 删除旧的DAO实现以及旧的schema 验证库(apis是使用它的最后一个实体),在自定义插件中使用新的 schema format。
  • 为了简化插件的转换,1.0中的 plugin loader 包含 best-effort 的模式自动翻译器,对于许多插件来说应该足够了。
  • 在0.14.x版本的Upstreams中,Targets 和 Plugins 仍然使用旧的 DAO 和Admin API实现。在0.15.0和1.0.0上,所有核心实体都使用新的kong.db DAO,并且他们的端点已升级到新的Admin API(有关详细信息,请参阅下文)。#3689, #3739, #3778
  • 新的迁移框架( migration framework),#3802
  • luaossl 版本跳提升到20181207#4067
  •  kong.resty.getssl 模块 #3681
  • 时间戳现在允许毫秒精度#3660
  • OpenSSL 已经提升到至 1.1.1a #4005
  • luasec 提升到 to 0.7
  • PDK函数 kong.request.get_body 现在将返回nilerrmime,当body是有效的JSON但是既不是对象也不是数组#4063

New Admin API引入的更改摘要:

  • 分页已包含在所有“multi-record”端点中,分页控制字段与0.14.x中的不同。
  • 现在通过URL路径更改(/consumers/x/plugins)而不是querystring字段(/plugins?consumer_id = x)进行过滤。
  • Array values不能与逗号分隔的字符串相交。它们必须是JSON请求上的“正确”JSON值,或者在form-url-encoded或multipart请求上使用新语法。
  • 错误消息已经从头开始重新设计,更加一致,准确和提供信息。
  • PUT方法已经使用幂等行为重新实现,并且已添加到一些没有它的实体中。

有关New Admin API的更多详细信息请访问官方文档https://docs.konghq.com/

配置

  • 删除了custom_plugins指令(自2018年7月的0.14.0起不推荐使用)。请改用plugins

插件

  • 删除了galileo插件(自0.13.0起不推荐使用)
  • 在0.14.0中引入插件开发工具包(PDK)之前,插件作者偶尔使用的一些内部模块现已被删除:
    • kong.tools.ip 模块已被删除。请改用PDK中的kong.ip
    • kong.tools.public 模块已被删除。请使用PDK中的各种等效功能。
    • kong.tools.responses 模块已被删除。请改用PDK中的 kong.response.exit。您可能还想使用kong.log.err来记录内部服务器错误。
    • kong.api.crud_helpers模块已删除(自0.13.0中引入新DAO以来已弃用)。如果需要自定义自动生成的端点,请使用kong.api.endpoints
  • 在插件模式中,no_routeno_serviceno_consumer注释被制作为相应字段的#decection#3739;在0.15中,它们在schema.lua table 中作为ad-hoc字段提供,作为旧的no_consumer选项。
  • 所有自带的插件模式和自定义实体都已更新为新的kong.db,并且他们的API已更新为New Admin API,因此得到了改进,但是仍有不同的行为,如上一节所述#3766, #3774, #3778, #3839
  • 所有插件迁移都已转换为新的迁移框架。自定义插件需要使用0.15以上的新迁移框架。

附加

Service Mesh 和 Stream Routes

  • 这些新功能需要修补版本的OpenResty,但Kong仍然可以在非修补的OpenResty for HTTP(S)API网关方案中正常工作
  • 通过stream_listen配置选项支持TCP和TLSStream Routes #4009
  • 新的origins配置属性允许覆盖来自kong的主机 #3679
  • Kong实例现在可以创建共享内部Certificate Authority,,用于Service Mesh SSL流量 #3906, #3861,
  • transparent 监听允许使用 iptables 设置Service Mesh [#3884]
  • 插件的run_on字段用于控制它们在Service Mesh环境中的行为方式 #3930, #4066
  • 这里新加一个叫做preread的新阶段。这是流量路由完成的地方。

核心

  • 路由现在有一个name字段 [#3764]
  • 在新的DAO和Admin API中实现了TTL支持。特别是,PostgreSQL获得了一种新的更高效的TTL实现 #3603, #3638
  • 通过减少数据库访问量来提高路由器重建的性能 #3782
  • Schema 改进:
    • Subschemas 子模式 #3630
    • 新的实体验证器:distinctneis_regexcontainsgt
    • 实体检查仅在必要时运行 #3848
    • 条件验证器可以根据需要标记字段 6d1707c4s
    • 记录字段的部分更新 05adc40f
    • 向schema添加具有默认值的新字段不再需要迁移 #3756
  • PDK改进:
    • 新的kong.node模块 #3826
    • 新的 kong.response.get_path_with_query 模块 #3842
    • PDK getters and setters for Service, Route, Consumer & Credential #3916
    • kong.response.get_source返回error错误 #4006
    • kong.response.exit可以在header_filter阶段使用,但只能没有body #4039
  • Cluster-wide mutex 集群范围的互斥锁 #3685
  • 向Admin API添加多部分支持: #3776
  • 改进了插件迭代器的速度 #3794
  • 在活动运行状况检查中添加对HTTPS的支持 #3815

配置

  • 新字段 dns_valid_ttl #3730
  • 新字段 pg_timeout #3808
  • 设置为0时,可以禁用 upstream_keepalive (感谢 @pryorda! ) #3716
  • 新的transparent后缀也适用于proxy_listen指令

插件

  • http-log插件现在接受缓冲日志记录 #3604
  • 大多数插件逻辑都是用PDK重写的,而不是使用内部kong函数或ngx调用 #3845
  • 新的run_on选项用于控制插件在Service Mesh环境中的执行位置 #3930, #4066
  • 通常,插件对故障/意外输入更具弹性 #4006, #3947, #4038
  • AWS现在支持使用is_proxy_integration进行Lambda代理集成#3427。感谢@aloisbarreras 的补丁。

修复项

核心

插件

  • 记录字段在插件架构中不可为空 #3778
  • 修复了一些问题,其中一些插件可能包含Lapis的默认HTML响应 #4077
  • cors:
    •  Access-Control-Allow-Credentials 启用的时候 set ‘Vary: Origin’(感谢@marckhouzam #3675
    • 对于预检请求,返回HTTP 200而不是204 (感谢 @aslafy-z) #4029)
    • 现在可以安全地验证 flat strings 。0eaa9acd
  • acl:
    • 编辑ACL时会重置缓存 #3839
    • 缓存正确用于 intermediary #4040
  • correlation-id:当access阶段被跳过的时候会报错 #3924
  • aws-lambda: HTTP / 2不允许去掉header #f2ee98e2
  • ratelimiting & response-ratelimiting:修复了不必要的redis调用问题:redis:select 可以关闭连接。(感谢 @fffonion #3973

Openresty 第三方库 Lua_resty_http 使用教程

lua_resty_http是一个第三方 openresty 库,基于 Openresty/ngx_lua 的HTTP客户端,支持POST方法上传数据,刚好项目中用到需要从网关中发起请求,于是就用到这个库,把使用方式在这里分享一下。

安装第三方库lua_resty_http

第一步

首先找到项目地址:https://github.com/pintsized/lua-resty-http

第二步

然后将 lua-resty-http/lib/resty/ 目录下的 http.lua  http_headers.lua 两个文件拷贝到 /usr/local/openresty/lualib/resty 目录下即可,OpenResty 安装目录为 /usr/local/openresty)。不需要重启。(少数需要清空 Openresty shared_dict 数据的情况需要重启 )。

代码示例

local function HttpUtil(jwt_data)
    -- 引入第三方库
    local http = require "resty.http"
    local httpc = http.new()
    -- 需要post的参数
    local str = "aaa=1&bbb=2%ccc=3"
    -- 请求地址
    local url = "http://wwww.xxxxxxx.com"
    local res, err = httpc:request_uri(url, {
        method = "POST",
        body = str,
        headers = {
            ["Content-Type"] = "application/x-www-form-urlencoded",
            ["Content-Length"] = #str,
        }
    })

    -- 返回值
    ngx.say(res.body)
    ngx.say(res.status)
    ngx.say(res.headers)

    return res.body,res.status
end

参数详解

请求参数

参数名 描述
version HTTP版本号,目前支持1.0或1.1
method HTTP方法
path 路径
query 查询字符串,表示为文字字符串或Lua table
headers 请求 header table
body 请求体作为字符串或迭代器函数(请参阅get_client_body_reader)。
ssl_verify 验证SSL证书是否与主机名匹配

返回参数

请求成功后,res将包含以下字段:

参数名 描述
status 状态码
reason 状态原因短语
headers headers 类型是table ,相同名称的header会合并成一个table
has_body bool值,指示是否有要读取的正文
body_reader 迭代器函数,用于以流方式读取正文。
read_body 一种将整个主体读入字符串的方法。
read_trailers 读取正文后,合并标题下trailers的方法。

参考链接

微服务 API 网关 Kong JWT插件中文文档

原文链接: https://docs.konghq.com/hub/kong-inc/jwt/
(如有翻译的不准确或错误之处,欢迎留言指出)

验证包含HS256或RS256签名JSON Web令牌的请求(如RFC 7519中所述)。每个消费者都将拥有JWT凭证(公钥和密钥),这些凭证必须用于签署其JWT。然后可以通过令牌传递如下:

  • 查询字符串参数
  • 一个cookie
  • 或者带有 Authorization 的头

如果验证了令牌的签名,Kong会将请求代理到您的上游服务,否则将丢弃该请求。Kong还可以对RFC 7519(exp和nbf)的一些注册声明进行验证。

相关术语

  • plugin:在请求被代理到上游API之前或之后,在Kong内部执行操作的插件
  • Service:表示外部上游API或微服务的Kong实体。
  • Route:Kong实体表示将下游请求映射到上游服务的方法
  • upstream service:这是指位于Kong后面的您自己的API /服务,转发客户端请求
  • API:上游服务的实例。在CE 0.13.0 and EE 0.32版本后被弃用,替换为service

配置

在service上启用插件

通过发出以下请求在service上配置此插件:

$ curl -X POST http://kong:8001/services/{service}/plugins \
    --data "name=jwt"
  • service:此插件将要代理的service的id或者name

在路由上启用插件

通过以下请求在router上配置:

$ curl -X POST http://kong:8001/routes/{route_id}/plugins \
    --data "name=jwt"
  • rouer_id:将要启动插件的路由id

在API上启用插件

如果您正在使用老版本的 Kong(在CE 0.13.0 and EE 0.32版本后被弃用,替换为service) 。您可以通过发出以下请求在此类API之上配置此插件:

$ curl -X POST http://kong:8001/apis/{api}/plugins \
    --data "name=jwt"
  • api:此插件配置将定位的API的ID或名称。

全局插件

可以使用http://kong:8001/plugins/配置所有插件,一个插件跟任何service ,router, api 或者 Consumer 没有强关联,都可以考虑把它做成全局插件,将在每个请求上运行,有关更多信息,请阅读插件参考插件优先级相关文档。

参数

以下是可在此插件配置中使用的所有参数的列表:

参数名称 默认值 描述
name 要使用的插件的名称,在本例中为jwt
service_id 此插件将定位的服务的ID。
route_id 此插件将定位的路由的ID。
enabled true 是否将应用此插件
api_id 此插件配置将定位的API的ID或名称。(在CE 0.13.0 and EE 0.32版本后被弃用,替换为service)
config.uri_param_names(可选) jwt Kong用来查询JWT字符串的uri参数列表。
config.cookie_names(可选) Kong用来查询JWT字符串的ucookies参数列表。
config.claims_to_verify(可选) 需要被验证的声明(也就是payload),支持的值为 exp, nbf
config.key_claim_name(可选) iss 需要被验证的key标示的名称,从0.13.1开始插件将尝试按此顺序从JWT有效负载和标题中读取此声明。
config.secret_is_base64(可选) false 如果为true,则插件假定凭证的秘密为base64编码。您需要为您的消费者创建base64编码的秘密,并使用原始密码签署您的JWT。
config.anonymous(可选) 如果身份验证失败,则用作“匿名”使用者的可选字符串(使用者uuid)值。如果为空(默认),请求将失败,并且身份验证失败4xx。请注意,此值必须引用Kong内部的Consumer id属性,而不是其custom_id。
config.run_on_preflight(可选) true 指示插件是否应在OPTIONS预检请求上运行(并尝试进行身份验证),如果设置为false,则始终允许OPTIONS请求。 (此参数仅适用于版本0.11.1及更高版本)
config.maximum_expiration(可选) 0 JWT的生命周期限制为将来的maximum_expiration秒的整数。任何具有更长生命周期的JWT都将被拒绝(HTTP 403)。如果指定了这个值,则还必须在claim_to_verify属性中指定exp。默认值0表示无限期。配置此值时应考虑潜在的时钟偏差。

文档

为了使用该插件,首先需要创建一个Consumer然后关联一个或多个JWT凭证(保存用于验证令牌的公钥和私钥)。 消费者代表了开发人员使用最终服务。

创建一个Consumer

您需要将credential与现有的Consumer对象相关联。要创建使用者,您可以执行以下请求:

$ curl -X POST http://kong:8001/consumers \
    --data "username=<USERNAME>" \
    --data "custom_id=<CUSTOM_ID>"
HTTP/1.1 201 Created
参数 默认值 描述
username (半可选) Consumer的用户名,custom_id和username必须至少有一个
custom_id (半可选) 用于将Consumer映射到外部数据库的自定义标识符。custom_id和username必须至少有一个

一个Consumer可以拥有许多JWT凭证。

创建一个 JWT credential

您可以通过发出以下HTTP请求来配置新的HS256 JWT凭证:

$ curl -X POST http://kong:8001/consumers/{consumer}/jwt -H "Content-Type: application/x-www-form-urlencoded"
HTTP/1.1 201 Created

{
    "consumer_id": "7bce93e1-0a90-489c-c887-d385545f8f4b",
    "created_at": 1442426001000,
    "id": "bcbfb45d-e391-42bf-c2ed-94e32946753a",
    "key": "a36c3049b36249a3c9f8891cb127243c",
    "secret": "e71829c351aa4242c2719cbfbe671c09"
}
  • consumer: 通过 id 或者 username 把 credential 关联到相对应credential
参数 默认值 描述
key(可选) 标识凭证的唯一字符串。如果不传的话将自动生成一个.
algorithm(可选) HS256 用于验证令牌签名的算法.可选值为HS256, HS384, HS512, RS256, ES256.
rsa_public_key(可选) 如果参数 algorithm  RS256 或者 ES256 ,则用于验证令牌签名的公钥(采用PEM格式)。
secret(可选) 如果参数 algorithm  RS256 或者 ES256 ,用于为此凭证签署JWT的秘钥.如果不传的话将自动生成一个.

删除一个 JWT credential

您可以通过发出以下HTTP请求来删除Consumer的JWT:

$ curl -X DELETE http://kong:8001/consumers/{consumer}/jwt/{id}
HTTP/1.1 204 No Content
  • consumer : 通过 id 或者 username 把 credential 关联到相对应credential
  • id: JWT credential 的id

JWT credential 列表

您可以通过发出以下HTTP请求列出Consumer的JWT凭证:

$ curl -X GET http://kong:8001/consumers/{consumer}/jwt
HTTP/1.1 200 OK
  • consumer: 通过 id 或者 username 把 credential 关联到相对应credential
{
    "data": [
        {
            "rsa_public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgK .... -----END PUBLIC KEY-----",
            "consumer_id": "39f52333-9741-48a7-9450-495960d91684",
            "id": "3239880d-1de5-4dbc-bccf-78f7a4280f33",
            "created_at": 1491430568000,
            "key": "c5a55906cc244f483226e02bcff2b5e",
            "algorithm": "RS256",
            "secret": "b0970f7fc9564e65xklfn48930b5d08b1"
        }
    ],
    "total": 1
}

创建一个带秘钥的JWT(HS256)

既然您的消费者拥有凭证,并且假设我们想要使用HS256进行签名,那么JWT应按照以下方式制作(RFC 7519):

首先,它的header必须是

{
    "typ": "JWT",
    "alg": "HS256"
}

然后,claims参数中必须包含秘钥的key,在config.key_claim_name配置中.该声明默认为iss(发行者字段),将其值设置为我们先前创建的凭证key,claims可能包含其他值。自Kong 0.13.1起,将会在 JWT 的payload和header中都会查找该字段.

{
    "iss": "a36c3049b36249a3c9f8891cb127243c"
}

可以在https://jwt.io 中调试 JWT ,header (HS256), claims (iss, etc),秘钥字段绑定key(e71829c351aa4242c2719cbfbe671c09),你将会得到这样的一个字符串

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhMzZjMzA0OWIzNjI0OWEzYzlmODg5MWNiMTI3MjQzYyIsImV4cCI6MTQ0MjQzMDA1NCwibmJmIjoxNDQyNDI2NDU0LCJpYXQiOjE0NDI0MjY0NTR9.AhumfY35GFLuEEjrOXiaADo7Ae6gt_8VLwX7qffhQN4

发起一个带有JWT的请求

现在,可以把JWT以添加在HEADER中的形式来发起一个请求:

$ curl http://kong:8000/{route path} \
    -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhMzZjMzA0OWIzNjI0OWEzYzlmODg5MWNiMTI3MjQzYyIsImV4cCI6MTQ0MjQzMDA1NCwibmJmIjoxNDQyNDI2NDU0LCJpYXQiOjE0NDI0MjY0NTR9.AhumfY35GFLuEEjrOXiaADo7Ae6gt_8VLwX7qffhQN4'

如果在配置文件中配置了config.uri_param_names字段,也可以把JWT以url参数的形式传入: 声明必须包含秘密的密钥字段(这不是用于生成令牌的私钥,而只是该配置声明中的标识符)(来自config.key_claim_name)。

curl http://kong:8000/{route path}?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhMzZjMzA0OWIzNjI0OWEzYzlmODg5MWNiMTI3MjQzYyIsImV4cCI6MTQ0MjQzMDA1NCwibmJmIjoxNDQyNDI2NDU0LCJpYXQiOjE0NDI0MjY0NTR9.AhumfY35GFLuEEjrOXiaADo7Ae6gt_8VLwX7qffhQN4

如果在配置文件中配置了config.cookie_names,也可以cookies的形式传入:

curl --cookie jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhMzZjMzA0OWIzNjI0OWEzYzlmODg5MWNiMTI3MjQzYyIsImV4cCI6MTQ0MjQzMDA1NCwibmJmIjoxNDQyNDI2NDU0LCJpYXQiOjE0NDI0MjY0NTR9.AhumfY35GFLuEEjrOXiaADo7Ae6gt_8VLwX7qffhQN4 http://kong:8000/{route path}

这个请求将会被kong检查,取决于验证字段是否有效

请求 是否被代理到上游服务 响应状态码
没有携带JWT串 no 401
缺失了 iss claim no 401
无效签名 no 403
有效签名 yes 代理上游的请求返回值
有效签名,但是没有 iss claim no 403

提示:当JWT有效并代理上游服务时,除了添加标识Consumer的标头之外,不会对请求进行任何修改。 JWT将会被转发给上游服务,该服务可以检验此jwt的合法性。 然后上游服务的作用是base64解码JWT然后使用。

(可选)验证claims

RFC 7519中所定义,Kong还可以对已注册的claims执行验证。要对声明claims验证,请将其添加到config.claims_to_verify属性:

可以给已经存在的jwt插件补充如下:

# 增加了对 nbf 和 exp claims的验证:
curl -X PATCH http://kong:8001/plugins/{jwt plugin id} \
    --data "config.claims_to_verify=exp,nbf"

支持的claims

claim 名称 校验
exp JWT 是否过期
nbf 校验是否过期

(可选) Base64 encoded 秘钥

如果你的秘密包含二进制数据,你可以将它们存储为Kong中的base64编码。

可以给已经存在的router补充如下:

$ curl -X PATCH http://kong:8001/routes/{route id}/plugins/{jwt plugin id} \
    --data "config.secret_is_base64=true"

或者已经存在的api:

$ curl -X PATCH http://kong:8001/apis/{api}/plugins/{jwt plugin id} \
    --data "config.secret_is_base64=true"

然后base64 encode consumers的 secrets:

# secret is: "blob data"
curl -X POST http://kong:8001/consumers/{consumer}/jwt \
  --data "secret=YmxvYiBkYXRh"

使用JWT 的 public/private keys (RS256 or ES256)

如果你想使用RS256 / ES256 来验证JWT,那么创建一个JWT的credential,选择RS256 或者 ES256 作为 algorithm,然后在rsa_public_key直接上传public key(包含 ES256 签名过的token)

$ curl -X POST http://kong:8001/consumers/{consumer}/jwt \
      -F "rsa_public_key=@/path/to/public_key.pem" \
HTTP/1.1 201 Created

{
    "consumer_id": "7bce93e1-0a90-489c-c887-d385545f8f4b",
    "created_at": 1442426001000,
    "id": "bcbfb45d-e391-42bf-c2ed-94e32946753a",
    "key": "a36c3049b36249a3c9f8891cb127243c",
    "rsa_public_key": "-----BEGIN PUBLIC KEY----- ..."
}

创建签名的时候,header 会是这样:

{
    "typ": "JWT",
    "alg": "RS256"
}

然后,claims 必须包含秘密的key字段(这不是用于生成令牌的private key,而只是该配置的claim)(来自config.key_claim_name)。 该claim 默认为iss(发行者字段),将其值设置为我们先前创建的credential的 key.claims可能包含其他值.自Kong 0.13.1起,将会在 JWT 的payload和header中都会查找该字段.

{
    "iss": "a36c3049b36249a3c9f8891cb127243c"
}

接着,然后使用您的私钥创建签名。 使用https://jwt.io 上的JWT调试器,设置正确的header(RS256),claims(iss等)和相关的 public key。 然后将结果值附加到Authorization header中,例如:

$ curl http://kong:8000/{route path} \
    -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIxM2Q1ODE0NTcyZTc0YTIyYjFhOWEwMDJmMmQxN2MzNyJ9.uNPTnDZXVShFYUSiii78Q-IAfhnc2ExjarZr_WVhGrHHBLweOBJxGJlAKZQEKE4rVd7D6hCtWSkvAAOu7BU34OnlxtQqB8ArGX58xhpIqHtFUkj882JQ9QD6_v2S2Ad-EmEx5402ge71VWEJ0-jyH2WvfxZ_pD90n5AG5rAbYNAIlm2Ew78q4w4GVSivpletUhcv31-U3GROsa7dl8rYMqx6gyo9oIIDcGoMh3bu8su5kQc5SQBFp1CcA5H8sHGfYs-Et5rCU2A6yKbyXtpHrd1Y9oMrZpEfQdgpLae0AfWRf6JutA9SPhst9-5rn4o3cdUmto_TBGqHsFmVyob8VQ'

生成一个 public/private keys

要创建一对全新的public/private keys,可以运行以下命令:

$ openssl genrsa -out private.pem 2048

这个私钥必须保密。要生成与私钥对应的公钥,执行

$ openssl rsa -in private.pem -outform PEM -pubout -out public.pem

如果运行上述命令,则公钥将写入public.pem,而私钥将写入private.pem。

在JWT插件中使用Auth0

Auth0是一种流行的授权解决方案,并且在很大程度上依赖于JWT。 Auth0依赖于RS256,不进行base64编码,并公开托管用于签署令牌的公钥证书。 出于指南的目的,帐户名称被称为“COMPANYNAME”。

要开始,请创建service,使用该服service的router或创建API。
注意:Auth0不使用base64编码的秘密。

创建一个service:

$ curl -i -f -X POST http://localhost:8001/services \
    --data "name=example-service" \
    --data "=http://httpbin.org"

然后创建一个router

$ curl -i -X POST http://localhost:8001/apis \
    --data "name={api}" \
    --data "hosts=example.com" \
    --data "upstream_url=http://httpbin.org"

添加JWT插件 添加插件到你的router

$ curl -X POST http://localhost:8001/route/{route id}/plugins \
    --data "name=jwt"

添加插件到你的api

$ curl -X POST http://localhost:8001/apis/{api}/plugins \
    --data "name=jwt"

下载你的Auth0帐户的X509证书:

$ curl -o {COMPANYNAME}.pem https://{COMPANYNAME}.auth0.com/pem

从X509证书中提取公钥:`

$ openssl x509 -pubkey -noout -in {COMPANYNAME}.pem > pubkey.pem

使用 Auth0 public key 创建一个Consumer:

curl -i -X POST http://kong:8001/consumers \
    --data "username=<USERNAME>" \
    --data "custom_id=<CUSTOM_ID>"

curl -i -X POST http://localhost:8001/consumers/{consumer}/jwt \
    -F "algorithm=RS256" \
    -F "rsa_public_key=@./pubkey.pem" \
    -F "key=https://{COMPAYNAME}.auth0.com/" # the `iss` field

默认情况下,JWT插件会针对令牌中的iss字段验证key_claim_name。Auth0颁发的密钥将其iss字段设置为http://{COMPANYNAME}.auth0.com/.在创建Consumer时,可以使用jwt.io验证key参数的iss字段。

通过发送请求,只有Auth0签名的令牌才能正常工作:

$ curl -i http://localhost:8000 \
    -H "Host:example.com" \
    -H "Authorization:Bearer "

成功!

上游 Headers

当JWT有效时,Consumer已经过身份验证,插件会在将请求代理到上游服务之前将一些头附加到请求中,以便您可以在代码中识别Consumer:

  • X-Consumer-ID, Consumer 在 Kong 的 ID
  • X-Consumer-Custom-ID, Consumer的custom_id (如果存在)
  • X-Consumer-Username, Consumer的username (如果存在)
  • X-Anonymous-Consumer,身份验证失败时将设置为true,并设置“匿名”使用者。

您可以使用此信息来实现其他逻辑。 您可以使用X-Consumer-ID值来查询Kong Admin API并检索有关Consumer的更多信息。

通过JWT分页

提示:此功能在Kong 0.11.2中引入。

您可以使用以下请求为所有使用者分配JWT:

$ curl -X GET http://kong:8001/jwts

{
    "total": 3,
    "data": [
        {
            "created_at": 1509593911000,
            "id": "381879e5-04a1-4c8a-9517-f85fbf90c3bc",
            "algorithm": "HS256",
            "key": "UHVwIly5ZxZH7g52E0HRlFkFC09v9yI0",
            "secret": "KMWyDsTTcZgqqyOGgRWTDgZtIyWeEtJh",
            "consumer_id": "3c2c8fc1-7245-4fbb-b48b-e5947e1ce941"
        },
        {
            "created_at": 1511389527000,
            "id": "0dfc969b-02be-42ae-9d98-e04ed1c05850",
            "algorithm": "ES256",
            "key": "vcc1NlsPfK3N6uU03YdNrDZhzmFF4S19",
            "secret": "b65Rs6wvnWPYaCEypNU7FnMOZ4lfMGM7",
            "consumer_id": "c0d92ba9-8306-482a-b60d-0cfdd2f0e880"
        },
        {
            "created_at": 1509593912000,
            "id": "d10c6f3b-71f1-424e-b1db-366abb783460",
            "algorithm": "HS256",
            "key": "SqSNfg9ARmPnpycyJSMAc2uR6nxdmc9S",
            "secret": "CCh6ZIcwDSOIWacqkkWoJ0FWdZ5eTqrx",
            "consumer_id": "3c2c8fc1-7245-4fbb-b48b-e5947e1ce941"
        }
    ]
}

您可以使用以下查询参数过滤列表:

属性 描述
id(可选) 基于JWT credential ID字段的列表上的过滤器。
key(可选) 基于JWT credential key 字段的列表上的过滤器。
consumer_id(可选) 基于JWT credential consumer_id字段的列表上的过滤器。
size(可选) 要返回的对象数量的限制(默认100)
offset(可选) 用于分页的游标。offset是一个对象标识符,用于定义列表中的位置。

检索与JWT关联的使用者

提示:此功能在Kong 0.11.2中引入。

可以使用以下请求检索与JWT关联的 Consumer 

$ curl -X GET http://kong:8001/jwts/{key or id}/consumer

{
   "created_at":1507936639000,
   "username":"foo",
   "id":"c0d92ba9-8306-482a-b60d-0cfdd2f0e880"
}

`key` or id: JWT的idkey属性,用于获取关联的Consumer。

Kong初探 (插件开发以及使用)

Kong已有插件介绍

Kong Plugins中列出了已有的所有插件,有些插件只能在企业版使用,有些插件是社区成员开发的,大部分是Kong公司开发,并集成到社区版中。下面是社区版集成的、Kong公司维护的插件(2018-09-30 14:33:03):

认证插件:

  • Basic Auth
  • HMAC Auth
  • JWT Auth
  • Key Auth
  • LDAP Auth
  • OAuth 2.0 Auth

安全插件:

  • Bot Detection (机器人爬虫检测)
  • CORS (跨域请求)
  • IP Restriction (IP限制)

流控插件:

  • ACL (访问控制)
  • Rate Limiting (请求速率限制)
  • Request Size Limiting(返请求大小限制)
  • Request Termination (请求终止)
  • Response Rate Limiting (返回限速)

微服务插件:

  • AWS Lambda(无服务器计算平台)
  • Azure Functions(一个无服务器计算服务,使用它可以按需运行代码,而无需显式预配或管理基础结构。)
  • Apache OpenWhisk(开源的、事件驱动的计算平台)
  • Serverless Functions(无服务器架构)

分析和监控插件:

  • Datadog(记录API Metric如请求次数、请求大小、响应状态和延迟,可视化API Metric)
  • Prometheus(监控报警平台)
  • Zipkin(一款开源的分布式实时数据追踪系统。其主要功能是聚集来自各个异构系统的实时监控数据,用来追踪微服务架构下的系统延时问题)

内容修改插件:

  • Correlation ID(使用http头的唯一id传输来关联请求和返回)
  • Request Transformer(在转发到upstream之前修改请求)
  • Response Transformer(在upstream响应返回给客户端之前修改响应)

日志插件:

  • File Log
  • HTTP Log
  • Loggly
  • StatsD
  • Syslog
  • TCP Log
  • UDP Log

开发一个自己的插件

首先查看第一篇文章,保证你已经成功的安装以及启动了kong的服务,接下来第一件事情,就是要找到你的kong插件所在的位置 一般会在如下文件中,此文件夹就存放的是所有kong的插件位置,当然,你要写的插件也在这里

/usr/local/share/lua/5.1/kong/plugins/

在此文件下新建你的插件文件夹

touch /usr/local/share/lua/5.1/kong/plugins/testplugin

然后新建两个必须的文件,这两个文件是一个插件最基本的组成部分,其中,handler.lua  是插件核心,它是一个接口实现,其中每个函数将在请求生命周期中的期望时刻运行。schema.lua  用于定义插件配置

handler.lua  schema.lua

插件配置

Kong 插件通过schema.lua 文件定义配置。schema.lua  返回一个Table类型,包含no_consumer、fields、self_check三个属性:

属性名 Lua 类型 默认值 描述
no_consumer Boolean false 如果为true将不能应用此插件至指定消费者,只能被应用到 Services 或者 Routes, 例如:认证插件
fields Table {} 插件的 schema,使用一个键值对定义可用属性和他们的规则
self_check Function nil 如果在接受插件配置之前需要进行自定义验证,需要实现此函数

schema.lua  文件样本如下:

return {
  no_consumer = true, -- this plugin will only be applied to Services or Routes, 此插件是否用于所有用户
  fields = {
    -- Describe your plugin's configuration's schema here. 描述你的配置文件
  },
  self_check = function(schema, plugin_t, dao, is_updating)
    -- perform any custom verification 执行任何自定义的验证
    return true
  end
}

逻辑实现

Kong 插件可以在请求/响应生命周期中的几个入口点注入自定义逻辑,插件实现者必须在 handler.lua 中实现 base_plugin.lua  文件中的一个或多个接口。 base_plugin.lua  文件中的几个方法如下:

函数名 LUA-NGINX-MODULE Context 描述
:init_worker() init_worker_by_lua 在每个 Nginx 工作进程启动时执行
:certificate() ssl_certificate_by_lua 在SSL握手阶段的SSL证书服务阶段执行
:rewrite() rewrite_by_lua 从客户端接收作为重写阶段处理程序的每个请求执行。在这个阶段,无论是API还是消费者都没有被识别,因此这个处理器只在插件被配置为全局插件时执行
:access() access_by_lua 为客户的每一个请求而执行,并在它被代理到上游服务之前执行
:header_filter() header_filter_by_lua 从上游服务接收到所有响应头字节时执行
:body_filter() body_filter_by_lua 从上游服务接收的响应体的每个块时执行。由于响应流回客户端,它可以超过缓冲区大小,因此,如果响应较大,该方法可以被多次调用
:log() log_by_lua 当最后一个响应字节已经发送到客户端时执行

接下来找到你的conf文件

vim /etc/kong/kong.conf

找到其中这一行,去掉开头的注释并修改如下

plugins = bundled, testplugin

在testplugin目录执行如下命令

luarocks write_rockspec

会在本目录下生成一个 testplugin-scm-1.rockspec  文件

所以,一个最基本款的插件的结构将会是这样

testplugin/
├── handler.lua
├── schema.lua
└── testplugin-scm-1.rockspec

一个完整的插件目录结构应该像下面这样:

testplugin/
├── api.lua
├── daos.lua
├── handler.lua
├── migrations
│   ├── cassandra.lua
│   └── postgres.lua
└── schema.lua

 

其各个模块的功能如下:

模块名称 是否必须 描述
api.lua NO 插件需要向 Admin API 暴露接口时使用
daos.lua NO 数据层相关,当插件需要访问数据库时配置
handler.lua YES 插件的主要逻辑,这个将会被 Kong 在不同阶段执行其对应的 handler
migrations/*.lua NO 插件依赖的数据表结构,启用了 daos.lua 时需要定义
schema.lua YES 插件的配置参数定义,主要用于 Kong 参数验证

接着重启kong

kong stop
kong start -c /etc/kong/kong.conf

再到 http://localhost:8080 控制面板的插件列表中就能看到你的插件了。

日志

日志路径:

/usr/local/kong/logs/error.log

当然也可以在 /etc/kong/kong.conf  中找到配置日志路径修改即可

参考链接