apache / apisix

The Cloud-Native API Gateway
https://apisix.apache.org/blog/
Apache License 2.0
13.98k stars 2.45k forks source link

help request: What is the best way to dynamically route a cluster by token in customer plugin? #11342

Open xBoo opened 1 month ago

xBoo commented 1 month ago

Description

i got tenantid in jwt token, and i want to use this id to route the cluster, how can i do it ?

local jwt_obj = jwt:verify(conf.jwt_secret, token)
    if jwt_obj.valid and jwt_obj.verified then
        local tid = jwt_obj.payload.tid
        if tid ~= nil then
            local red, err = redis.new(conf)
            if not red then
                return 502, err
            end

            local domain, redis_err = red:get("tid-" .. tid)
            if not domain or domain == nil or (type(domain) == "userdata" and tostring(domain) == "userdata: NULL") then
                return 502, redis_err
            else
               -- Here I do not know,how can i set the  cluster domain?use the upstream id is the best way?
               --like this?  ctx.upstream_id = "512895159801742021"
                core.request.set_header(ctx, "x-cluster", domain)
            end
        else
            -- todo: add no token handle
            core.log.warn("tid is nil, set default cluster")
        end
    else
        core.log.warn("jwt valid error:" .. core.json.encode(jwt_obj))
        return 502, jwt_obj.reason
    end

Environment

shreemaan-abhishek commented 3 weeks ago

APISIX doesn't support this.

xBoo commented 3 weeks ago

I found an implementation, which is done through the following code: dymainc_uri_upstream.lua

 local up_conf = {
        timeout = {
            connect = 6,
            send = 300,
            read = 300
        },
        scheme = "http",
        type = "roundrobin",
        pass_host = "pass",
        keepalive_pool = {
            idle_timeout = 60,
            requests = 1000,
            size = 320
        },
        hash_on = "vars",
        nodes = {
            {
                priority = 0,
                port = upstream_port,
                host = parse_domain(upstream_host),
                weight = 1
            }
        }
    }

    local ok, err = upstream.check_schema(up_conf)
    if not ok then
        core.log.error("failed to validate generated upstream: ", err)
        return 500, err
    end

    local matched_route = ctx.matched_route
    up_conf.parent = matched_route
    local upstream_key = up_conf.type .. "#route_" .. matched_route.value.id
    core.log.info("upstream_key: ", upstream_key)

    upstream.set(ctx, upstream_key, ctx.conf_version, up_conf)

But I don't think it's a best practice because many parameters become fixed values and cannot be dynamically configured. I found that it can also be achieved by setting the upstream_id, but I don't know what the risks are.

xBoo commented 3 weeks ago

APISIX doesn't support this. Dynamic routing based on user (token) information is crucial in a multi-cluster mode, and I hope APISIX can implement this.