服务网关---基于Nginx+lua+Redis的IP校验模块设计

一:IP校验功能点
    1:只有被添加白名单的客户端才能调用,否则返回403
    2:容错机制,如果Redis宕机等异常,IP校验失效,所有客户端请求放行。
    3:动态添加白名单,增加nginx缓存,60s生效。

二:设计思路
    1:在Reids中把白名单IP添加到set中存储,Nginx把其加载到内存中,每隔60s刷新一次。
    2:获取客户端请求IP,在Nginx内存中读取白名单IP清单,如果不存在,即拦截请求返回403,否则方向通过。
    3:如果在连接Redis和从Redis中读取数据时发生异常,则放行请求,不再进行IP校验

三:设计原理图

四:附源码

--access_by_lua_file /home/lws/soft/openResty/nginx/conf/lua/IP_check.lua;
--lua_shared_dict ip_white_list 10m;
--需要先在redis中增加白名单:sadd 'white.ip' member
--如果redis宕机,不影响业务,全部放行通过,不进行ip校验
--增加缓存机制,减少redis数据读取消耗,缓存刷新时间60s

function ip_check(redis_ip, redis_port, redis_pwd, cli_IP, redis_ip_key)
    local redis = require "resty.redis"
    local ip_white_list = ngx.shared.ip_white_list;
    local last_update_time = ip_white_list:get("last_update_time")

    if last_update_time == nil or last_update_time < (ngx.now()-60) then
        --连接redis
        local red = redis.new()
        red:set_timeout(1000)
        local ok, err = red.connect(red, redis_ip, redis_port)
        if not ok then    
            errmsg = string.format("connect redis faild %s %s %s",redis_ip,redis_port,err)
            return -1, errmsg
        end
        --添加redis的auth认证,如果无auth,则不需要
        local count
        count, err = red:get_reused_times()
        if 0 == count then
            ok, err = red:auth(redis_pwd)
            if not ok then
                errmsg = string.format("failed to auth %s",err)
                return -2, errmsg
            end
        elseif err then
            errmsg = string.format("failed to get reused times %s",err)
            return -3, errmsg
        end

        local new_ip_white_list, err = red:smembers(redis_ip_key)
        if err then
            errmsg = string.format("Read Redis ip_white_list failed %s",err)
            return -4, errmsg
        else
            ip_white_list:flush_all()   --清空缓存
            for index, ip_white in ipairs(new_ip_white_list) do
                ip_white_list:set(ip_white,true)
            end
        end

        ip_white_list:set("last_update_time",ngx.now())

        -- 连接池大小是100个,并且设置最大的空闲时间是 10 秒
        local ok, err = red:set_keepalive(10000, 100)
        if not ok then
            errmsg = string.format("failed to set keepalive %s",err)
            return -5, errmsg
        end
    end

    if not ip_white_list:get(cli_IP) then
        errmsg = string.format("%s not in ip_white_list",cli_IP)
        return 1,errmsg
    end
    return 0, string.format("%s in ip_white_list", cli_IP)
end


local cli_IP = ngx.var.remote_addr
local redis_ip = '127.0.0.1'
local redis_port = '6379'
local redis_pwd = 'liws'
local redis_ip_key = 'white.ip'
ret, err = ip_check(redis_ip, redis_port, redis_pwd, cli_IP, redis_ip_key)
if ret == 1 then
    ngx.exit(ngx.HTTP_FORBIDDEN)
    return
elseif ret < 0 then
    ngx.log(ngx.ERR,err)
    return

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值