根据 JWT 的 key 和 URL 决定是否缓存 HTTP 请求


声明:本文转载自https://my.oschina.net/u/3720037/blog/1821676,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

链接 https://stackoverflow.com/questions/50605544/caching-api-requests-with-jwt-auth/50615736

需求

根据JWT的key和URL决定是否缓存HTTP请求

比如JWT里

payload: {   "iss": "iss",   "sub": "sub",   "userGroupID": "{userGroupID}" } 

然后请求 https://myapi.example.com/groups/{groupID}/cars

如果 userGroupID和groupID一样,则缓存,否则不缓存

解决方案

使用 https://github.com/jiangwenyuan/nuster 基于HAProxy的高性能缓存服务器

1. Download and build, you will need 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. create lua script, say, jwt_group_match.lua

-- base64 FROM http://lua-users.org/wiki/BaseSixtyFour  local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'  function 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  -- end base64   -- 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  -- end json       -- nuster jwt   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 = 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. create conf, say, 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. start nuster

./haproxy -f nuster.conf 

TEST

payload: {   "iss": "iss",   "sub": "sub",   "userGroupID": "nuster" }  curl http://127.0.0.1:8080/group/nuster/cars --header "jwt: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJpc3MiLCJzdWIiOiJzdWIiLCJ1c2VyR3JvdXBJRCI6Im51c3RlciJ9.hPpqQS0d4T2BQP90ZDcgxnqJ0AHmwWFqZvdxu65X3FM" 

First run

[CACHE] To create 

Second run

[CACHE] Hit 

本文发表于2018年05月31日 16:00
(c)注:本文转载自https://my.oschina.net/u/3720037/blog/1821676,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 1942 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1