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

林戈的IT生涯 2024-07-12 10:07:03 阅读 70

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

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

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

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

<code>#接口服务器负载

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. 截图如下:

    一开始看到这个问题,还真不知道从哪里下手,目测是哪里有什么特殊字符导致的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"code>

local t=explode(',', char)

for k,v in pairs(t) do

print(k.. '=>' .. v)

end

运行结果截图:



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。