给API接口增加Nginx+lua签名认证、Lua生成xml时特殊字符导致XML解析异常处理 及 Lua中find的妙用

给API接口增加Nginx+lua签名认证、Lua生成xml时特殊字符导致XML解析异常处理 及 Lua中find的妙用

码农世界 2024-06-16 后端 89 次浏览 0个评论

一、给API接口增加Nginx+lua签名认证

    一般我们在请求服务器端的接口时都需要进行签名认识,很多时候都是在PHP程序里将参数按照字母排序,然后连接成一个字符串,再加上一串独立密钥最后md5一下做成一个接口的认证,签名的基本原理也就这些东西,不过在PHP程序中做签名有个问题就是,如果需要自己调试接口的时候,每次参数有变化的时候都需要输入正确的sign签名字符串,才能顺利通过测试,而这会造成极大的不方便。

    之前在百度的时候,测试都是一个窗口打开着服务器端的错误日志,里面会记录传入的错误sign值和应该正确的sign值。可以想像这是多么麻烦。

    使用nginx+lua将签名独立出来就能避免这样的麻烦。比如下面的配置:

#接口服务器负载
upstream api_backends {
    server 127.0.0.1:80 weight=100;
    server 127.0.0.1:81 weight=100;
    keepalive 60;
}
#响应接口请求的location
location /sign/ {
    #lua_code_cache off;
    #由lua生成
    access_by_lua_file      /home/wwwroot/sign/sighcheck.lua;
    roxy_set_header         Host    "www.04007.cn";
    proxy_pass              http://api_backends;
}

     签名验证的工作全部交给access_by_lua_file      /home/wwwroot/sign/sighcheck.lua;这里来处理,nginx+lua处理速度也会比php快很多,处理完成后可直接在lua脚本中增加设置head头信息:

ngx.req.set_header("signCheck",0/1); 

    再在PHP程序中读取此信息以判断验证,甚至可以在nginx里直接阻止签名失败的请求,比如L:

location / {
    access_by_lua '
        local res = ngx.location.capture("/auth")
        if res.status
            ...
        end
    ';
    #再请求PHP
}

     这样的话,在测试环境中我们只需要修改nginx配置,过滤过签名验证就可以方便地进行测试。

二、Lua生成xml时内容中的特殊字符导致XML解析异常处理

    这前线上的XML文件一直正常,某天产品突然过来找到我,XML在浏览器中显示时报错:This page contains the following errors:error on line 1 at column 145975: Encoding error, Below is a rendering of the page up to the first error. 截图如下:

给API接口增加Nginx+lua签名认证、Lua生成xml时特殊字符导致XML解析异常处理 及 Lua中find的妙用

    一开始看到这个问题,还真不知道从哪里下手,目测是哪里有什么特殊字符导致的xml显示异常,但返回的内容太多,根本没法找到问题点。然后根据提示的错误,找到bytes在145975这个位置的内容,发现这个位置的内容确实有些异样,发现打印根本打印不出来这块字符(程序原来在处理时已经去掉了ascii码中小于32的字符),后来通过将字符串base64_encode后通过php解出来,显示出来了字符原型。它们是ASCII扩展字符128~255中的几个字符。临时加了对这几个字符的过滤,暂时解决了。但没过多久就发现其它的地方也有这样的问题,但是我在尝试将128-255的字符都删去,如下:

#lua代码示例
if string.byte(u8char) >= 128 and string.byte(u8char) <= 255 then
    #如果ascii码是扩展字符,就全部去掉
    return 
end

     但在操作时发现这样过滤,会将整个内容中的所有中文全部过滤掉了,因为中文的第一个字节就在这个范围。看来这种方式太简单粗暴。lua中用string.byte(s, i)取到字符的byte值。比较第一个字节是228-233,而且接下来两个字节都是 128-191,就可以简单认定为中文,找来一个使用lua过滤特殊字符,只保留中文、英文和数字的方法,用了可行。代码如下:

#lua过滤字符内容,只保留中文,英文和数据的方法
function filter_spec_chars(s)  
    local ss = {}  
    local k = 1  
    while true do  
        if k > #s then break end  
        local c = string.byte(s,k)  
        if not c then break end  
        if c<192 then  
            if (c>=48 and c<=57) or (c>= 65 and c<=90) or (c>=97 and c<=122) then  
                table.insert(ss, string.char(c))  
            end  
            k = k + 1  
        elseif c<224 then  
            k = k + 2  
        elseif c<240 then  
            if c>=228 and c<=233 then  
                local c1 = string.byte(s,k+1)  
                local c2 = string.byte(s,k+2)  
                if c1 and c2 then  
                    local a1,a2,a3,a4 = 128,191,128,191  
                    if c == 228 then a1 = 184  
                    elseif c == 233 then a2,a4 = 190,c1 ~= 190 and 191 or 165  
                    end  
                    if c1>=a1 and c1<=a2 and c2>=a3 and c2<=a4 then  
                        table.insert(ss, string.char(c,c1,c2))  
                    end  
                end  
            end  
            k = k + 3  
        elseif c<248 then  
            k = k + 4  
        elseif c<252 then  
            k = k + 5  
        elseif c<254 then  
            k = k + 6  
        end  
    end  
    return table.concat(ss)  
end

三、lua中利用find实现像Php里的explode方法一样切开字符串

    lua里面的函数库太少了,手册中的字符串函数就只有那么几个,相比于PHP一大堆的函数,真是不好用。但没办法,lua有lua的优点,还是得用起来,今天因为开发需要,要对字符串进行切割,一看手册,竟然没有这么简单常用的方法,找到了一个结合find,sub来进行切割的实现方法。用起来不错。

有时间真想好好整理好一个常用的lua程序库,避免大家都要去花时间找这个那个方法。

    最终实现代码如下:

--用到的几个string里的方法以及table中的insert
local find = string.find
local sub = string.sub
local insert = table.insert
--定义explode方法,参数delimeter即为切割符,str为目标符号。为PHP中的参数顺序一致。
function explode(delimeter, str)
    local res = {}
    --定义初始位置
    local start, start_pos, end_pos = 1, 1, 1
    --循环查找字符,每次往后移动一个位置
    while true do
        start_pos, end_pos = find(str, delimeter, start, true)
        if not start_pos then
            break
        end
        --找到字符后通过字符切割将内容保存至table
        insert(res, sub(str, start, start_pos - 1))
        start = end_pos + 1
    end
    --别忘了循环结束时还有末尾的内容要保存进来
    insert(res, sub(str,start))
    return res
end
--实例
local char="2013,2014,2015,2016"
local t=explode(',', char)
for k,v in pairs(t) do
    print(k.. '=>' .. v)
end

运行结果截图:

给API接口增加Nginx+lua签名认证、Lua生成xml时特殊字符导致XML解析异常处理 及 Lua中find的妙用

转载请注明来自码农世界,本文标题:《给API接口增加Nginx+lua签名认证、Lua生成xml时特殊字符导致XML解析异常处理 及 Lua中find的妙用》

百度分享代码,如果开启HTTPS请参考李洋个人博客
每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,89人围观)参与讨论

还没有评论,来说两句吧...

Top