openresty+lua做接口调用权限限制
说明:openresty可以理解为一个服务器它将nginx的核心包含了过来,并结合lua脚本语言实现一些对性能要求高的功能,该篇文章介绍了使用openresty
1.purview.lua
--调用json公共组件
cjson = require("cjson")
fun = require("ttq.fun") -- 引用公用方法文件
conf = require("ttq.ini") --引用配置文件
reds = require("ttq.redis_pool") --引用redis连接池
mysqld = require("ttq.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 ttq_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 ttq_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,"该项目鉴权成功,可以访问!"))
2.ini.lua
--配置相关方法
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
3.mysql_pool.lua
--连接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
4.redis_pool.lua
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
5.fun.lua
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 --检测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
6.配置nginx.conf文件
上面的lua文件都是放在/data/local/openresty/lualib/ttq/目录下
location /lua{
lua_code_cache on;
content_by_lua_file /data/local/openresty/lualib/ttq/purview.lua;
}
7.mysql数据设计
SET FOREIGN_KEY_CHECKS=0;
DROP TABLE IF EXISTS `ttq_appid_list`;
CREATE TABLE `ttq_appid_list` (
`id` int(4) unsigned NOT NULL AUTO_INCREMENT,
`appid` varchar(20) NOT NULL DEFAULT 'appid相当于项目名称',
`appkey` varchar(20) NOT NULL COMMENT 'appid密码',
`create_time` int(11) NOT NULL COMMENT '生产appid时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='项目appid对应关系表'; DROP TABLE IF EXISTS `ttq_appid_white_list`;
CREATE TABLE `ttq_appid_white_list` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`appid` char(20) NOT NULL COMMENT '项目标示或名称',
`ip` varchar(15) NOT NULL COMMENT '项目允许访问对应的ip地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB
8.访问方法
<form action="http://192.168.3.128:8083/lua" method="post">
<input type="text" name="appid" value='ttq'></input>
<input type="text" name="ip" value='192.168.3.2'></input>
<input type="text" name="appkey" value='67872'></input>
<input type="submit" value="鉴权check"></input>
</form>
9.压力测试
压力测试效果非常可观
qps可以达到2225
代码下载:
我的github代码地址:https://github.com/lisiqiong/learning/tree/master/luacode
openresty+lua做接口调用权限限制的更多相关文章
- windows下openresty中使用lua做接口转发、二次封装等
需求:根据客户需求,可以在ngx下 通过lua做接口二次封装再次转发给用户或第三方 场景:对返回值有要求的.接口屏蔽字段.或做一些业务上的验证等 1.windows直接下载openresty 解压即可 ...
- OpenResty Lua钩子调用完整流程
前面一篇文章介绍了Openresty Lua协程调度机制,主要关心的是核心调度函数run_thread()内部发生的事情,而对于外部的事情我们并没有涉及.本篇作为其姊妹篇,准备补上剩余的部分.本篇将通 ...
- 微信调用照相拍照等 js 接口的权限配置 和 照片上传和下载实现
直接上代码: 1. 前端调试代码: <html> <head> <meta http-equiv="Content-Type" content=&qu ...
- tengine lua 开源一 调用内部接口高效发送文件
tengine lua 开源一 调用内部接口高效发送文件 开源自己封装的sendfile 模块,可以高效的通过lua发送文件 源码地址:https://github.com/weinyzhou/Lu ...
- openresty+lua+kafka方案与Tomcat接口并发度对比分析
1.openresty+lua+kafka 1.1 openresty+lua+kafka方案 之前的项目基于nginx反向代理后转发到Tomcat的API接口进行业务处理,然后将json数据打入ka ...
- 开源协同OA办公平台教程:O2OA服务管理中,接口的调用权限
本文介绍O2OA服务管理中,接口的权限设定和调用方式. 适用版本:5.4及以上版本 创建接口 具有服务管理设计权限的用户(具有ServiceManager角色或Manager角色)打开" ...
- 【精选】Nginx模块Lua-Nginx-Module学习笔记(一)Nginx Lua API 接口详解
源码地址:https://github.com/Tinywan/Lua-Nginx-Redis 一.介绍 各种* _by_lua,* _by_lua_block和* _by_lua_file配置指令用 ...
- Nginx模块Lua-Nginx-Module学习笔记(一)Nginx Lua API 接口详解
源码地址:https://github.com/Tinywan/Lua-Nginx-Redis 一.介绍 各种* _by_lua,* _by_lua_block和* _by_lua_file配置指令用 ...
- Openresty Lua协程调度机制
写在前面 OpenResty(后面简称:OR)是一个基于Nginx和Lua的高性能Web平台,它内部集成大量的Lua API以及第三方模块,可以利用它快速搭建支持高并发.极具动态性和扩展性的Web应用 ...
随机推荐
- DB2 设置最大连接数
db2 connect to dbname user username using passwd db2 update db cfg using MAXAPPLS number 查看最大连接数 查看D ...
- ios 第3天
在手动引用计数中 每一次调用 retain retainCount 就会加一 每一次release retainCount就会减一 当retainCount 为零时 就会free (p) ; ...
- Corosync+pacemaker实现集群的高可用
一.Corosync和pacemaker的了解: Corosync是集群管理套件的一部分,他在传递信息的时候可以通过一个简单的配置文件来定义信息传递的方式和协议等.也就是说,corosync是Mess ...
- phpMyAdmin 尝试连接到 MySQL 服务器,但服务器拒绝连接
phpMyAdmin 尝试连接到 MySQL 服务器,但服务器拒绝连接--解决方法 phpMyAdmin 尝试连接到 MySQL 服务器,但服务器拒绝连接.您应该检查配置文件中的主机.用户名和 ...
- TeamView
1.TeamView TeamViewer是一个能在任何防火墙和NAT代理的后台用于远程控制,桌面共享和文件传输的简单且快速的解决方案.为了连接到另一台计算机,只需要在两台计算机上同时运行 TeamV ...
- 从头搭建一个React应用
node,webpack这些就不一一介绍怎么安装了,默认大家都知道. 一.npm install -g create-react-app 首先全局安装react的脚手架工具 create-react- ...
- 【干货】Kaggle 数据挖掘比赛经验分享(mark 专业的数据建模过程)
简介 Kaggle 于 2010 年创立,专注数据科学,机器学习竞赛的举办,是全球最大的数据科学社区和数据竞赛平台.笔者从 2013 年开始,陆续参加了多场 Kaggle上面举办的比赛,相继获得了 C ...
- git pull时出现vim窗口的解决办法
最近常用到git来push代码到origin development分支上,也出现了几次vim窗口,防止忘记还是记录下来比较好: 首先按ESC键退出编辑状态,然后按shift+;键,再按wq!保存退出 ...
- Linux 去重 先sort再uniq
从uniq命令的帮助信息中可以看到,该命令只过滤相邻的重复行. 如果要去掉所有重复行,需要先排序,或者使用uniq -u $ uniq --h Usage: uniq [OPTION]... [INP ...
- C# http post上传文件
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.I ...