欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

网关kong自定义的插件开发攻略

程序员文章站 2024-03-24 18:46:04
...

如果你对网关kong是一片空白,建议先看我写的安装部署方案,

https://blog.csdn.net/fj56355113/article/details/107613497

开发初期需要对网关插件的原理有一些了解:

1、OpenResty:OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。具体查阅网站:http://openresty.org/cn/

2、Lua:是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。不要说你不会,哥也就花了1~2天的时候上车了。

3、Nginx:nginx我不想多说了,我只想说kong其实是在nginx的基础上做了一些API的管理,然后开放了一些不错的插件;

4、constants.lua:kong安装完成后,会默认在/usr/local/share/lua/5.1/kong路径下把核心的插件初始化,该constants.lua是定义所有插件的主入口,我们新增一个插件都要在这个文件中声明变量;

网关kong自定义的插件开发攻略

网关kong自定义的插件开发攻略

插件具体位置在/usr/local/share/lua/5.1/kong/plugins

网关kong自定义的插件开发攻略

本次举例采用插件名为extend-auth为例,所以在plugins中创建extend-auth文件夹,以下为详细举例:

插件的主要构成部分有handler.lua、schema.lua,这是游戏规则,不要问为什么。

1、schema.lua是插件在使用时配定义参数的主要脚本文件

例如:konga中找到自己的插件,需要使用时,

网关kong自定义的插件开发攻略

以下每一个参数都是要定义出来,具体看代码:

网关kong自定义的插件开发攻略

schema.lua详细代码如下:

-- extend-auth.schema.lua
local typedefs = require "kong.db.schema.typedefs"

return {
  name = "extend-auth",
  fields = {
    { consumer = typedefs.no_consumer },
    { config = {
        type = "record",
        fields = {
          { token_source_enums = { type = "set", elements = { type = "string" } } },
          { check_ip_url = typedefs.url({ required = true }) },
          { base_code = { type = "string", required = true, default = "DATA_CENTER" } },
          { app_key = { type = "string", required = true } },
          { secret_key = { type = "string", required = true } },
          { ext_url_path_enums = { type = "set", elements = { type = "string" } } }
        }, 
      },
    },
  }
}

2、handler.lua是插件被使用后,请求拦截后进入的主要方法;

local BasePlugin = require "kong.plugins.base_plugin"
local jwt_decoder = require "kong.plugins.extend-auth.jwt_parser"
local authHttp = require "kong.plugins.extend-auth.auth_http"

-- 字符串拆分函数
function Split(szFullString, szSeparator)
  local nFindStartIndex = 1
  local nSplitIndex = 1
  local nSplitArray = {}
  while true do
    local nFindLastIndex = string.find(szFullString, szSeparator, nFindStartIndex)
    if not nFindLastIndex then
      nSplitArray[nSplitIndex] = string.sub(szFullString, nFindStartIndex, string.len(szFullString))
      break
    end
    nSplitArray[nSplitIndex] = string.sub(szFullString, nFindStartIndex, nFindLastIndex - 1)
    nFindStartIndex = nFindLastIndex + string.len(szSeparator)
    nSplitIndex = nSplitIndex + 1
  end
  return nSplitArray
end

local CustomHandler = BasePlugin:extend()

CustomHandler.VERSION = "1.0.0"
CustomHandler.PRIORITY = 10

function CustomHandler:new()
  CustomHandler.super.new(self, "extend-auth")
end
function CustomHandler:access(config)
  -- 第一步:URL在配置范围内跳过校验(针对登录或者其它非授权页面)
  local urlPath = kong.request.get_path()
  if config.ext_url_path_enums ~= nil then
    for _, v in ipairs(config.ext_url_path_enums) do
      if v == urlPath then
        return
      end
    end
  end
  -- 第二步:获取Cookies中【tokenPre】令牌来源值
  local tokenPre = ngx.var.cookie_tokenPre
  -- 第三步:解析令牌来源,获取值如果是非内部令牌,非内部系统的范围值通过kong配置的枚举,跳过下面所有逻辑,由各个业务集成认证包去校验
  if tokenPre == nil then
    return kong.response.exit(401, "【tokenPre】不在设定范围内NULL", { ["Content-Type"] = "application/json;charset=UTF-8" } )
  end
  if tokenPre ~= "inside" and config.token_source_enums ~= nil then
    for _, v in ipairs(config.token_source_enums) do
      if v == tokenPre then
        return
      end
    end
    return kong.response.exit(401, "【tokenPre】不在设定范围内", { ["Content-Type"] = "application/json;charset=UTF-8" } )
  end
  -- 第四步:获取Cookies中【accessToken】访问令牌值
  local accessToken = ngx.var.cookie_accessToken
  if accessToken == nil then
    return kong.response.exit(401, "【accessToken】认证令牌失效", { ["Content-Type"] = "application/json;charset=UTF-8" } )
  end
  -- 第五步:解析访问令牌获取user_id,拿到user_id的值,该值的组成结构【INSIDE_B_819554】,如果是以【INSIDE_B_】开头则不进行URL校验逻辑
  local jwtAccessToken, err = jwt_decoder:new(accessToken)
  if err ~= nil then
    return kong.response.exit(401, "【accessToken】认证令牌失效,原因:" .. err, { ["Content-Type"] = "application/json;charset=UTF-8" } )
  end
  if jwtAccessToken.claims == nil or jwtAccessToken.claims.user_id == nil or 
     jwtAccessToken.claims.client_id == nil or jwtAccessToken.claims.expires_in == nil then
    return kong.response.exit(401, "【accessToken】认证令牌信息为空", { ["Content-Type"] = "application/json;charset=UTF-8" } )
  end
  local accessToken = jwtAccessToken.claims
  local clientId = accessToken.client_id
  local expiresIn = accessToken.expires_in
  local userArray = Split(accessToken.user_id, "_")
  if userArray ~= nil and userArray[1] ~= nil and userArray[2] ~= nil and userArray[3] ~= nil then
    if userArray[1] == "SEGI" and userArray[2] == "B" then
      -- 第六步:获取当前URL,问号以后的直接剔除
      local userId = userArray[3]
      -- 第七步:用user_id和URL去请求数据中心开放出来的API接口
      local checkIpUrl = config.check_ip_url
      local requestString = "{\"data\":{\"userId\":" .. userId .. ", \"url\":\"" .. urlPath .. "\", \"nOrgId\":0, \"channel\":1 }}"
      local respData, httpErr = authHttp.http_post_client(checkIpUrl, requestString, 5000)
      if httpErr ~= nil then
        return kong.response.exit(401, "【URL鉴权】校验异常" .. httpErr .. ",原因:" .. err, { ["Content-Type"] = "application/json;charset=UTF-8" } )
      else
        if respData ~= "0" then
          return kong.response.exit(401, "【URL鉴权】校验不通过respData:" .. respData, { ["Content-Type"] = "application/json;charset=UTF-8" } )
        end
      end
    end
  else
    return kong.response.exit(401, "【accessToken】认证令牌解析有误", { ["Content-Type"] = "application/json;charset=UTF-8" } )
  end
end

return CustomHandler

该实现的逻辑是根据我这边业务场景而写,里面具体内容可以不用关注,主要是给大家关注,kong的自定义插件怎么写。

local BasePlugin = require "kong.plugins.base_plugin"    # kong的基础类,所有自定义插件都是这样引入
local jwt_decoder = require "kong.plugins.extend-auth.jwt_parser"  # 为jwt解析类,可自己百度去找
local authHttp = require "kong.plugins.extend-auth.auth_http"         # 封装的HTTP请求第三方服务校验的客户端方法

注意几点:

1、每次插件写完后,需要重启kong,重启命令: kong restart -c /etc/kong/kong.conf --vv

2、如果插件中有语法错误,重启会失败,可以查阅日志找问题,日志位置在/usr/local/kong/logs/error.log

网关kong自定义的插件开发攻略

相关标签: 负载均衡