云实验室(18) - kong扩展redis-auth插件

1. 编写插件

代码参考 https://hub.fastgit.org/duyhotan2000/kong-plugin-auth-redis 感谢原作者的开源工作. 我们做了少量修改,结构效果如下:

代码源码 :

handle.lua

代码语言:javascript
复制
-- Extending the Base Plugin handler is optional, as there is no real
-- concept of interface in Lua, but the Base Plugin handler's methods
-- can be called from your child implementation and will print logs
-- in your `error.log` file (where all logs are printed).
local BasePlugin = require "kong.plugins.base_plugin"
local RedisToken = BasePlugin:extend()

local header_filter = require "kong.plugins.auth-redis.header_filter"

-- Your plugin handler's constructor. If you are extending the
-- Base Plugin handler, it's only role is to instanciate itself
-- with a name. The name is your plugin name as it will be printed in the logs.
function RedisToken:new()
RedisToken.super.new(self, "auth-redis")
end

function RedisToken:access(config)
-- Eventually, execute the parent implementation
-- (will log that your plugin is entering this context)
RedisToken.super.access(self)

header_filter.execute(config, ngx)
end

return RedisToken

header_filter.lua

代码语言:javascript
复制
local redis = require "resty.redis"

local _M = {}

function _M.execute(conf, ngx)

-- Get request Header and check if exist
local ngx_headers = kong.request.get_headers()
local auth, err = ngx_headers["Authorization"]
if not auth and conf.allow_anonymous == 0 then -- 1 = Allow anonymous forward request, 0 = Disallow, return 401 as default
return kong.response.exit(401, { message = "Unauthorized" })
end

if not auth and conf.allow_anonymous == 1 then
kong.service.request.clear_header("Authorization")
return
end

-- Init Redis connection
local red = redis:new()
red:set_timeout(conf.redis_timeout)

-- Connect to redis
local ok, err = red:connect(conf.redis_host, conf.redis_port)
if not ok then
return kong.response.exit(503, "Session Service Temporarily Unavailable")
end
-- end

-- Auth Redis connection with password
if conf.redis_password and conf.redis_password ~= "" then
local ok, err = red:auth(conf.redis_password)
if not ok then
return kong.response.exit(503, "Session Service Temporarily Unavailable")
end
end

-- Query token in Redis
local token = auth
--if string.len(conf.redis_token_prefix) > 0 then
-- token = conf.redis_token_prefix .. ":" .. string.sub(auth, 8)
--else
-- token = string.sub(auth, 8)
--end

local verify, err = red:get(token)
kong.log("verify", verify);
if err then
return kong.response.exit(503, "Session Service Temporarily Unavailable")
end
if not verify then
return kong.response.exit(503, "Session Service Temporarily Unavailable")
end

-- Keep Established Redis connection
local ok, err = red:set_keepalive(60000,5000)
if not ok then
kong.log.err("failed to set Session keepalive: ", err)
end

if verify == ngx.null then
return kong.response.exit(401, { message = "Unauthorized" })
elseif conf.allow_anonymous == 1 then
kong.service.request.clear_header("Authorization")
return
else
kong.service.request.set_header("Authorization", "Bearer " .. verify)
end

-- Close Redis connection
-- local ok, err = red:close()
end

return _M

schema.lua

代码语言:javascript
复制
local redis = require "resty.redis"

return {
fields = {
redis_token_prefix = {
type = "string",
default = ""
},
redis_host = {
type = "string"
},
redis_port = {
type = "number",
default = 6379
},
redis_password = {
type = "string"
},
redis_timeout = {
type = "number",
default = 2000
},
allow_anonymous = {
type = "number",
default = 0
}
},
self_check = function(schema, plugin_t, dao, is_updating)
if not plugin_t.redis_host then
return false, kong.response.exit(500, "You need to specify a Redis host")
elseif not plugin_t.redis_port then
return false, kong.response.exit(500, "You need to specify a Redis port")
elseif not plugin_t.redis_timeout then
return false, kong.response.exit(500, "You need to specify a Redis timeout")
end

    local red = redis:new()
    red:set_timeout(plugin_t.redis_timeout)
    local ok, err = red:connect(plugin_t.redis_host, plugin_t.redis_port)
    if not ok then
        return false, kong.response.exit(500, "Redis Host unreachable: " .. err)
    end

    if plugin_t.redis_password and plugin_t.redis_password ~= "" then
        local ok, err = red:auth(plugin_t.redis_password)
        if not ok then
            return false, kong.response.exit(500, "Redis Invalid Credentials: " .. err)
        end
    end

    return true
end

}

2. 将插件挂载到kong

3.1 插件挂载

3.2 kong配置挂载(constants.lua)

3.3 修改(constants.lua)

3.4 重启kong

3.5 konga添加插件

3. 测试

3.1 请求 head 中没有放 "Authorization"

3.2 请求 head 中加上 "Authorization"

3.3 redis中添加key

3.4 再次请求

正常响应了

3.5 查看kong日志

用户信息已经放入了http head中,下游可直接食用,不在依赖进程会话.