zl程序教程

您现在的位置是:首页 >  其他

当前栏目

Kong 优雅实现微服务网关鉴权,登录场景落地实战篇

2023-03-31 10:34:41 时间

目录

  • 登录实现
    • B 端登录之后,浏览器存 cookie
    • 登录代码实现细节,cookie设计
  • 网关介绍
    • API 网关是什么
    • 为什么需要网关
    • 从技术角度来看,什么是Kong?
    • 为什么使用 Kong
  • Kong 网关解析 cookie
    • kong 项目简介,流量转发
    • 鉴权 lua 脚本
    • 服务解析请求
  • 此方案实现的优缺点
    • 单点登录问题
    • 登录续期问题
    • 注销问题

登录实现

Kong 项目构成

这个项目只是做了鉴权,属于内网网关,流量在这之前还会经过一道外网网关,那边有流控,请求分发,配置证书等功能,内网网关只是做鉴权,流量打到这边鉴权之后不同的路由转发到 k8s 的不同 service 里调用具体的服务。

项目部署了线上网关和测试环境网关两种环境,提供的plugins插件鉴权有 APP端的鉴权,C端和B端鉴权,这里我主要讲的是B端的鉴权,其他的简单介绍一下:

  • shop-resolve 里面主要是 小程序和H5 两种环境下的店铺信息鉴权,是公司一个电商项目需要用的;
  • idk-client-type-resolve 里面主要是 小程序和H5 两种环境下的访问鉴权;
  • health-check 没什么好说的,是k8s的健康检查需要的
  • 其他三个 app-resolve,buser-reslove,cuser-resolve 分别是app环境,B端,C端的鉴权

B端鉴权lua脚本

local ngx_re = require "ngx.re"
local BasePlugin = require "kong.plugins.base_plugin"
local string = require "resty.string"
local BuserResolveHandler = BasePlugin:extend()

function BuserResolveHandler:new()
    BuserResolveHandler.super.new(self, "buser-resolve")
end

function BuserResolveHandler:access(conf)
    BuserResolveHandler.super.access(self)
    local cookieName = "cookie_" .. "KUAIZHAN_V2"
    local kuaizhanV2 = ngx.var[cookieName]
--     ngx.log(ngx.ERR, "kuaizhanV2", kuaizhanV2)
    local uid = 0
    ngx.req.set_header("X-User-Id", uid)
  
    // cookie 内容 3001459%7C1636684996%7C7180720502%7Cb61a12ef865072964aa359e6a9ef2e0b1846dee9
    if xxx_V2 and xxx_V2 ~= '' then
        local res, err = ngx_re.split(xxxV2, "%7C")
        if err then
            return
        end
        // 解析得到 userId, time, nonce, sign,
        // 分别为 3001459,1636684996,7180720502,b61a12ef865072964aa359e6a9ef2e0b1846dee9
        local userId, time, nonce, sign = res[1], res[2], res[3], res[4]
        // 根据密钥,时间,签名,利用 hmac_sha1 算法,十六进制算法,得到摘要签名
        local digest = ngx.hmac_sha1(conf.secret, userId .. time .. nonce)
        local theSign = string.to_hex(digest)
        -- TODO 加上过期时间判断
        // 计算签名和cookie解析得到sign 是否相同,相同则赋值uid
        if theSign == sign then
            uid = userId
        end
        ngx.log(ngx.ERR, "theSign:", theSign, "sign:", sign, "uid:", uid)
    end

    ngx.log(ngx.ERR, "get x-user-id:" .. uid)
    // nginx 请求头header里面存放 X-User-Id,再转发到各个业务线
    ngx.req.set_header("X-User-Id", uid)
end

return BuserResolveHandler

但是多端,或者跨顶域情况下的单点登录是没法做的。

登录续期问题

不知道大家有没有关注到第一张 cookie 截图后面有个失效时间,这种由于依赖 cookie,因此只要到期就会被踢下线,需要重新登录,一定程度上影响客户体验。

现在的很多应用都利用 token + redis 方案实现了登录续期,例如连续十天内有过登录,那么不需要再次登录,后端实现自动续期,十天以上都没有登录过的才失效需要重新登录。

但是续期服务需要 redis 成本,这种省成本。

注销问题

这种方案的注销,只是简单的删除 cookie,如果有心人拿到 cookie 仍然是可以用的,这个 cookie 在有效期内不会失效。

token+redis 方案可以做到真实的 token 失效。