lua鉴权

简介

openresty+lua做接口调用权限限制
说明:openresty可以理解为一个服务器它将nginx的核心包含了过来,并结合lua脚本语言实现一些对性能要求高的功能

purview.lua

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
--调用json公共组件  
cjson = require("cjson")  
fun = require("myxz.fun") -- 引用公用方法文件  
conf = require("myxz.ini") --引用配置文件  
reds = require("myxz.redis_pool") --引用redis连接池  
mysqld = require("myxz.mysql_pool") --引用mysql连接池  
--参数校验  
check_arg =   fun:check_post_arg() --调用参数校验方法  
arg_tables = {} --存储post的参数信息  
if check_arg['status'] ==0 then  
    --参数校验通过,获取返回的参数,并将参数拼接  
    arg_tables= check_arg['arg_tables']  
    get_info = string.format("%s:%s:%s",arg_tables['appid'],arg_tables['ip'],arg_tables['appkey'])  
else  
    ngx.say(fun:resJson(-1,check_arg['msg']))  
    return;  
end  
   
--1.首先通过redis查找  
--2.没有找到再找数据库  
--3.根据appid查询项目是否授权  
--4.项目获取权限成功,再查询ip是否被限制了  
local res,err,value = reds:get_key(get_info)  
if not res then  
    ngx.say(fun:resJson(-1,err))  
    return  
end  
if value == ngx.null then  
        
    --redis数据未空,根据appid查询,查询信息是否一致  
    local sql_appid =  string.format("select * from myxz_appid_list   where appid= '%s' and appkey='%s'   limit 1 ",arg_tables['appid'],arg_tables['appkey'])    
    local res,msg,result = mysqld:query(sql_appid)  
    --连接失败报错  
    if not res then  
        ngx.say(fun:resJson(-1,msg))  
    end  
        
    --未查找数据报错  
    if table.maxn(result)== 0 then  
        ngx.say(fun:resJson(-1,'appid验证失败,被拦截'))  
        return  
    end  
   
    --项目权限获取成功,需要验证ip是否被允许  
    local sql = string.format("select * from myxz_appid_white_list where appid='%s' and ip= '%s' limit 1 ",arg_tables['appid'],arg_tables['ip'])  
    res,msg,result = mysqld:query(sql)  
    if table.maxn(result)==0 then  
        ngx.say(fun:resJson(-1,'该项目,非法操作或没有授予权限,被拦截'))  
        return  
    end  
   
    --所有验证通过,最后写入redis缓存  
    ok, err = reds:set_key(get_info,1)  
    ngx.say(fun:resJson(0,'该项目鉴权成功,可以访问'));  
    return  
end  
--3.redis找到了信息鉴权成功  
ngx.say(fun:resJson(0,"该项目鉴权成功,可以访问!"))  

—|—

ini.lua

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
--配置相关方法  
local _CONF = {}  
--返回redis配置文件  
function _CONF.redis()  
    local  redis_config = {host='127.0.0.1',pass='123456',port=6379} --redis配置项  
    return redis_config  
end  
   
--返回mysql配置文件  
function _CONF.mysql()  
    local mysql_config = {host='127.0.0.1',port=3306,database='test',user='root',password='123456'} --mysql的配置项  
    return mysql_config  
end  
   
return _CONF  

—|—

mysql_pool.lua

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
--连接mysql  
local mysql = require "resty.mysql"  
local mysql_pool = {}  
function mysql_pool:get_connect()  
if ngx.ctx[mysql_pool] then  
    return true,'返回mysql连接池成功',ngx.ctx[mysql_pool]  
end  
local db, err_mysql = mysql:new()  
if not db then  
    return false,"failed to instantiate mysql"  
end  
db:set_timeout(1000) -- 1 sec  
local ok, err_mysql, errno, sqlstate = db:connect{  
    host = conf.mysql()['host'],  
    port = conf.mysql()['port'],  
    database = conf.mysql()['database'],  
    user = conf.mysql()['user'],  
    password = conf.mysql()['password'],  
    max_packet_size = 1024 * 1024  
}  
if not ok then  
--ngx.say(fun.resJson(-1,"mysql connect failed"))  
return false,"mysql conncet failed"  
end  
--存储mysql连接池并返回  
ngx.ctx[mysql_pool] = db  
return true,'mysql连接成功',ngx.ctx[mysql_pool]  
   
end  
   
   
--关闭mysql连接池  
function mysql_pool:close()  
if ngx.ctx[mysql_pool] then  
ngx.ctx[mysql_pool]:set_keepalive(60000, 1000)  
ngx.ctx[mysql_pool] = nil  
end  
end  
   
   
--执行sql查询  
function mysql_pool:query(sql)  
--ngx.say(sql)  
local ret,msg,client = self:get_connect()  
--连接数据库失败,返回错误信息  
if not ret then  
return false,msg  
end  
--连接成功后执行sql查询,执行失败返回错误信息  
local res,errmsg,errno,sqlstate = client:query(sql)  
--self:close()  
if not res then  
return false,errmsg  
end  
--ngx.say(res[1]['appid'])  
--ngx.say(res[1]['ip'])  
--执行成功,返回信息  
return true,"查询信息成功",res  
end  
   
return mysql_pool  

—|—

redis_pool.lua

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
local redis = require("resty.redis")  
local redis_pool = {}  
--连接redis  
function redis_pool:get_connect()  
    if ngx.ctx[redis_pool] then  
        return true,"redis连接成功",ngx.ctx[redis_pool]  
    end  
    local red = redis:new()  
    red:set_timeout(1000) -- 1 sec  
    local ok, err = red:connect(conf.redis()['host'],conf.redis()['port'])  
if not ok then  
    return false,"failed to connect redis"  
end  
--设置redis密码  
local count, err = red:get_reused_times()  
if 0 == count then  
    ok, err = red:auth(conf.redis()['pass'])  
if not ok then  
    return false,"redis failed to auth"  
end  
    elseif err then  
        return false,"redis failed to get reused times"  
end  
--选择redis数据库  
ok, err = red:select(0)  
if not ok then  
    return false,"redis connect failed "  
end  
--建立redis连接池  
ngx.ctx[redis_pool] = red  
    return true,'redis连接成功',ngx.ctx[redis_pool]  
end  
   
--关闭连接池  
function redis_pool:close()  
    if ngx.ctx[redis_pool] then  
        ngx.ctx[redis_pool]:set_keepalive(60000, 300)  
        ngx.ctx[redis_pool] = nil  
    end  
end  
---获取key的值  
function redis_pool:get_key(str)  
    local res,err,client = self:get_connect()  
    if not res then  
        return false,err  
    end  
local keys = client:get(str)  
--self:close()  
    return true,"获取key成功",keys  
end  
   
--设置key的值  
function redis_pool:set_key(str,value)  
    local res,err,client = self:get_connect()  
        if not res then  
    return false,err  
end  
client:set(str,value)  
--self:close()  
return true,"成功设置key"  
end  
   
return redis_pool  

—|—

fun.lua

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
local _M = {}  
  
--返回json信息公用方法  
function _M:resJson(status,mes)  
    local arr_return = {}  
    arr_return['status'] = status  
    arr_return['msg'] = mes  
    return cjson.encode(arr_return)  
end  
  
--字符串按指定字符拆分公用方法  
function _M:lua_string_split(str, split_char)      
    local sub_str_tab = {};   
    while (true) do          
        local pos = string.find(str, split_char);    
        if (not pos) then              
            local size_t = table.getn(sub_str_tab)  
            table.insert(sub_str_tab,size_t+1,str);  
            break;    
            end  
      
        local sub_str = string.sub(str, 1, pos - 1);                
        local size_t = table.getn(sub_str_tab)  
        table.insert(sub_str_tab,size_t+1,sub_str);  
        local t = string.len(str);  
        str = string.sub(str, pos + 1, t);     
    end      
    return sub_str_tab;  
end  
  
  
--检测post过来的参数合法性  
function _M:check_post_arg()  
    local rule_count =  3  
    --接收POST过来的数据  
    ngx.req.read_body()  
    local arg = ngx.req.get_post_args()  
    local arg_count = 0 --存储参数个数  
    local arg_table = {appid,ip,appkey}  
    local get_info --参数拼接字符串,方便redis操作  
    --遍历post过来的参数  
    for k,v in pairs(arg) do  
        arg_count = arg_count+1  
        arg_table[k] = v  
    end  
  
    --参数赋值  
    appid = arg_table['appid']   
    ip = arg_table['ip']  
    appkey = arg_table['appkey']  
    --判断参数个数传递过来的参数要与规定的个数一致  
    if rule_count == arg_count then  
        if string.len(appid) == 0 then  
            return  {status=-1,msg='参数传递错误,被拦截'}  
        end  
        if string.len(ip) == 0 then   
            return  {status=-1,msg='参数传递错误,被拦截'}  
        end  
        if string.len(appkey) == 0 then   
            return  {status=-1,msg='参数传递错误,被拦截'}  
        end   
        ---参数正确返回参数信息  
        return  {status=0,msg='参数校验成功',arg_tables=arg_table}  
    else  
        return  {status=-1,msg='参数传递错误,被拦截'}  
    end  
end  
  
return _M  

—|—

配置nginx.conf文件

1  
2  
3  
4  
5  
上面的lua文件都是放在/data/local/openresty/lualib/myxz/目录下  
location /lua{  
lua_code_cache on;  
content_by_lua_file /data/local/openresty/lualib/myxz/purview.lua;  
}  

—|—

mysql数据

糖果

糖果
LUA教程

Lapis框架的常用处理方法

Lapis框架的常用处理方法 Continue reading

MoonScript实现选择排序

Published on February 26, 2017

MoonScript与Redis客户端

Published on January 19, 2017