Kong 扩展jwt插件增加黑名单验证

喜你入骨 提交于 2020-10-10 08:04:13

jwt-blacklist

扩展官方jwt插件,保留token过期及签名验证, 增加根据jti查询redis黑名单数据库,实现单一登录和强制下线。

扩展功能

  • 增加可配置在header中添加userId
  • 增加可配置的在转发到上游服务前,删除header中的jwt
  • 优化配置参数,删除从cookie获取token,支持从url和header获取token,增加redis配置,增加默认值。
  • 验证payload是否含有jti,没有返回401。
  • 验证jti是否在黑名单,若在返回401和对应的value。

注意

  1. 此插件依赖官方jwt插件读写数据库,不能单独使用
  2. 插件支持解析如下jwt格式
{
  "sub": "k4usr2v6an",
  "user_name": "球场",
  "origin": {
    "status": "AccountVerification",
    "msg": "账号已验证",
    "users": [
      {
        "userId": "k4usr2v6an",
        "type": "MOBILE",
        "account": "130******71",
        "mobile": "130******71",
        "loginName": "球场",
        "nickName": "球场"
      }
    ]
  },
  "scope": [
    "read",
    "write"
  ],
  "exp": 1590635506,
  "authorities": [
    "USER"
  ],
  "jti": "20220bd3-a0c9-4318-bb35-c07e9611668c",
  "client_id": "pc"
}
{
  "exp": 1590603064,
  "user_name": "k1jdxqwrda",
  "authorities": [
    "ROLE_DEVELOPER",
    "ROLE_STUDENT"
  ],
  "jti": "c8365700-0791-45d6-9e4d-ad1a669815bf",
  "client_id": "dev-client",
  "scope": [
    "read",
    "write"
  ]
}

使用

1. 增加一个service,url为http://mockbin.org/request

2. 增加一个router,path为/mock

3. 增加jwt插件,配置如下

4. 调用我们的授权服务获取一个access_token

5. 添加一个CONSUMER,配置jwt key和公钥

6. 在redis数据库中增加key为prefix+jti

7. 携带token访问service,验证结果

核心代码

{ redis_host = {
                    type = "string",
                    required = true,
                    default = "127.0.0.1"
                } },
                { redis_port = {
                    type = "number",
                    required = true,
                    default = 6379
                } },
                { redis_db = {
                    type = "number",
                    required = true,
                    default = 0
                } },
                { redis_password = {
                    type = "string",
                } },
                { string_key_prefix = {
                    type = "string",
                    required = true,
                    default = "userOffline:"
                } },
function checkJti(conf, jti)
    if not jti then
        return false, { status = 401, message = "Invalid jti in claims" }
    end
    local red = redis:new()
    red:set_timeout(1000)
    local ok, err = red:connect(conf.redis_host, conf.redis_port)
    if not ok then
        kong.log.err("failed to connect : ", err)
        return
    end
    if conf.redis_password and conf.redis_password ~= "" then
        local count
        count, err = red:get_reused_times()
        if 0 == count then
            ok, err = red:auth(conf.redis_password)
            if not ok then
                kong.log.err("failed to auth: ", err)
                return
            end
        elseif err then
            kong.log.err("failed to get reused times: ", err)
            return
        end
    end
    ok, err = red:select(conf.redis_db)
    if not ok then
        kong.log.err("failed to select db: ", err)
        return
    end
    -- get key
    local res, err = red:get(conf.string_key_prefix .. jti)
    kong.log.notice("red:get:", conf.string_key_prefix .. jti, ",value=", res)
    if err then
        kong.log.err("failed to get key", conf.string_key_prefix .. jti)
    end
    --连接池大小是100个,并且设置最大的空闲时间是 10 秒
    ok, err = red:set_keepalive(10000, 100)
    if not ok then
        kong.log.err("failed to set keepalive: ", err)
        return
    end
    if res ~= ngx.null then
        return false, { status = 401, message = res }
    end
    return true
end

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!