gpt4 book ai didi

php - 使用JWT auth缓存API请求

转载 作者:行者123 更新时间:2023-12-03 17:46:44 25 4
gpt4 key购买 nike

我一直在尝试找出是否可以缓存需要JWT身份验证的请求并检查 token 内容。

当前设置:

  • PHP API
  • Nginx服务请求

  • 我一直在探索的软件:
  • Nginx
  • Varnish

  • 代币内容:
  • iss ...(常规JWT内容)
  • userGroupID

  • 我为用户提供了一些共享的内容,有些是个人的。因此,我希望能够将请求缓存到某些端点。当缓存中有可用数据时,甚至无需调用PHP。

    假设我们有用户组和组自己的汽车。我希望能够对以下端点进行身份验证和缓存请求:
    https://myapi.example.com/groups/{groupID}/cars

    要验证此请求,缓存软件必须能够将{groupID}与 token 中的groupID进行比较。但是afaik Varnish只能验证 token ,但是可以检查 token 的groupID与URL中的groupID匹配吗?

    Nginx具有一些JWT功能,但是在这里找不到任何可以实现的功能:
    https://nginx.org/en/docs/http/ngx_http_auth_jwt_module.html

    是否有其他软件可以达到此目的?现在,我正在考虑回到PHP中的缓存内容。在此处检查 token ,并使用memcached或其他方式缓存数据。

    最佳答案

    您可以使用 https://github.com/jiangwenyuan/nuster ,一个基于 HAProxy 的缓存代理服务器

    1. 下载并编译,你需要lua

    wget https://github.com/jiangwenyuan/nuster/releases/download/v1.8.8.2/nuster-1.8.8.2.tar.gz

    make TARGET=linux2628 USE_ZLIB=1 USE_OPENSSL=1 USE_LUA=1 LUA_LIB=/opt/lua-5.3.1/lib LUA_INC=/opt/lua-5.3.1/include

    2. 创建lua脚本:base64.lua, json.lua, jwt_group_match.lua

    base64.lua
    -- base64 FROM http://lua-users.org/wiki/BaseSixtyFour

    local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'

    base64 = {}

    function base64.dec(data)
    data = string.gsub(data, '[^'..b..'=]', '')
    return (data:gsub('.', function(x)
    if (x == '=') then return '' end
    local r,f='',(b:find(x)-1)
    for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
    return r;
    end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
    if (#x ~= 8) then return '' end
    local c=0
    for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
    return string.char(c)
    end))
    end

    return base64

    json.lua
    -- json FROM https://gist.github.com/tylerneylon/59f4bcf316be525b30ab
    json = {}


    function kind_of(obj)
    if type(obj) ~= 'table' then return type(obj) end
    local i = 1
    for _ in pairs(obj) do
    if obj[i] ~= nil then i = i + 1 else return 'table' end
    end
    if i == 1 then return 'table' else return 'array' end
    end

    function escape_str(s)
    local in_char = {'\\', '"', '/', '\b', '\f', '\n', '\r', '\t'}
    local out_char = {'\\', '"', '/', 'b', 'f', 'n', 'r', 't'}
    for i, c in ipairs(in_char) do
    s = s:gsub(c, '\\' .. out_char[i])
    end
    return s
    end

    function skip_delim(str, pos, delim, err_if_missing)
    pos = pos + #str:match('^%s*', pos)
    if str:sub(pos, pos) ~= delim then
    if err_if_missing then
    error('Expected ' .. delim .. ' near position ' .. pos)
    end
    return pos, false
    end
    return pos + 1, true
    end

    function parse_str_val(str, pos, val)
    val = val or ''
    local early_end_error = 'End of input found while parsing string.'
    if pos > #str then error(early_end_error) end
    local c = str:sub(pos, pos)
    if c == '"' then return val, pos + 1 end
    if c ~= '\\' then return parse_str_val(str, pos + 1, val .. c) end
    -- We must have a \ character.
    local esc_map = {b = '\b', f = '\f', n = '\n', r = '\r', t = '\t'}
    local nextc = str:sub(pos + 1, pos + 1)
    if not nextc then error(early_end_error) end
    return parse_str_val(str, pos + 2, val .. (esc_map[nextc] or nextc))
    end

    function parse_num_val(str, pos)
    local num_str = str:match('^-?%d+%.?%d*[eE]?[+-]?%d*', pos)
    local val = tonumber(num_str)
    if not val then error('Error parsing number at position ' .. pos .. '.') end
    return val, pos + #num_str
    end

    json.null = {} -- This is a one-off table to represent the null value.

    function json.parse(str, pos, end_delim)
    pos = pos or 1
    if pos > #str then error('Reached unexpected end of input.') end
    local pos = pos + #str:match('^%s*', pos) -- Skip whitespace.
    local first = str:sub(pos, pos)
    if first == '{' then -- Parse an object.
    local obj, key, delim_found = {}, true, true
    pos = pos + 1
    while true do
    key, pos = json.parse(str, pos, '}')
    if key == nil then return obj, pos end
    if not delim_found then error('Comma missing between object items.') end
    pos = skip_delim(str, pos, ':', true) -- true -> error if missing.
    obj[key], pos = json.parse(str, pos)
    pos, delim_found = skip_delim(str, pos, ',')
    end
    elseif first == '[' then -- Parse an array.
    local arr, val, delim_found = {}, true, true
    pos = pos + 1
    while true do
    val, pos = json.parse(str, pos, ']')
    if val == nil then return arr, pos end
    if not delim_found then error('Comma missing between array items.') end
    arr[#arr + 1] = val
    pos, delim_found = skip_delim(str, pos, ',')
    end
    elseif first == '"' then -- Parse a string.
    return parse_str_val(str, pos + 1)
    elseif first == '-' or first:match('%d') then -- Parse a number.
    return parse_num_val(str, pos)
    elseif first == end_delim then -- End of an object or array.
    return nil, pos + 1
    else -- Parse true, false, or null.
    local literals = {['true'] = true, ['false'] = false, ['null'] = json.null}
    for lit_str, lit_val in pairs(literals) do
    local lit_end = pos + #lit_str - 1
    if str:sub(pos, lit_end) == lit_str then return lit_val, lit_end + 1 end
    end
    local pos_info_str = 'position ' .. pos .. ': ' .. str:sub(pos, pos + 10)
    error('Invalid json syntax starting at ' .. pos_info_str)
    end
    end

    return json

    jwt_group_match.lua
    base64 = require("base64")
    json = require("json")

    function jwt_group_match(txn)

    local hdr = txn.http:req_get_headers()
    local jwt = hdr["jwt"]
    if jwt == nil then
    return false
    end

    _, payload, _ = jwt[0]:match"([^.]*)%.([^.]*)%.(.*)"
    if payload == nil then
    return false
    end

    local payload_dec = base64.dec(payload)
    local payload_json = json.parse(payload_dec)

    if txn.sf:path() == "/group/" .. payload_json["userGroupID"] .. "/cars" then
    return true
    end
    return false
    end

    core.register_fetches("jwt_group_match", jwt_group_match)

    3. 创建 conf,比如 nuster.conf
    global
    nuster cache on dict-size 1m data-size 100m
    debug
    lua-load jwt_group_match.lua

    frontend web1
    bind *:8080
    mode http

    default_backend app1

    backend app1
    mode http
    http-request set-var(req.jwt_group_match) lua.jwt_group_match

    nuster cache on
    nuster rule group if { var(req.jwt_group_match) -m bool }


    server s1 127.0.0.1:8000
    server s2 127.0.0.1:8001

    3. 启动 nuster
    ./haproxy -f nuster.conf

    测试
    payload: {
    "iss": "iss",
    "sub": "sub",
    "userGroupID": "nuster"
    }

    curl http://127.0.0.1:8080/group/nuster/cars --header "jwt: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJpc3MiLCJzdWIiOiJzdWIiLCJ1c2VyR3JvdXBJRCI6Im51c3RlciJ9.hPpqQS0d4T2BQP90ZDcgxnqJ0AHmwWFqZvdxu65X3FM"

    首轮
    [CACHE] To create

    第二次运行
    [CACHE] Hit

    对于 Auth 部分,您可以使用 https://github.com/SkyLothar/lua-resty-jwt

    关于php - 使用JWT auth缓存API请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50605544/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com