博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
golang接口IP限流,IP黑名单,IP白名单
阅读量:3987 次
发布时间:2019-05-24

本文共 3254 字,大约阅读时间需要 10 分钟。

增加中间件

可以选择普通模式和LUA脚本模式,建议选择普通模式,实际上不需要控制的那么精确。

package Middlewaresimport (	"github.com/gin-gonic/gin"	"strconv"	"time"	"voteapi/pkg/app/response"	"voteapi/pkg/gredis"	"voteapi/pkg/util")const IP_LIMIT_NUM_KEY = "ipLimit:ipLimitNum"const IP_BLACK_LIST_KEY = "ipLimit:ipBlackList"var prefix = "{gateway}"var delaySeconds int64 = 60   // 观察时间跨度,秒var maxAttempts int64 = 10000 // 限制请求数var blackSeconds int64 = 0   // 封禁时长,秒,0-不封禁func GateWayPlus() gin.HandlerFunc {
return func(c *gin.Context) {
path := c.FullPath() clientIp := c.ClientIP() // redis配置集群时必须 param := make(map[string]string) param["path"] = path param["clientIp"] = clientIp if !main(param) {
c.Abort() response.JsonResponseError(c, "当前IP请求过于频繁,暂时被封禁~") } }}func main(param map[string]string) bool {
// 预知的IP黑名单 var blackList []string if util.InStringArray(param["clientIp"], blackList) {
return false } // 预知的IP白名单 var whiteList []string if util.InStringArray(param["clientIp"], whiteList) {
return false } blackKey := prefix + ":" + IP_BLACK_LIST_KEY limitKey := prefix + ":" + IP_LIMIT_NUM_KEY curr := time.Now().Unix() item := util.Md5(param["path"] + "|" + param["clientIp"]) return normal(blackKey, limitKey, item, curr)}// 普通模式func normal(blackKey string, limitKey string, item string, time int64) (res bool) {
if blackSeconds > 0 {
timeout, _ := gredis.RawCommand("HGET", blackKey, item) if timeout != nil {
to, _ := strconv.Atoi(string(timeout.([]uint8))) if int64(to) > time {
// 未解封 return false } // 已解封,移除黑名单 gredis.RawCommand("HDEL", blackKey, item) } } l, _ := gredis.RawCommand("HGET", limitKey, item) if l != nil {
last, _ := strconv.Atoi(string(l.([]uint8))) if int64(last) >= maxAttempts {
return false } } num, _ := gredis.RawCommand("HINCRBY", limitKey, item, 1) if ttl, _ := gredis.TTLKey(limitKey); ttl == int64(-1) {
gredis.Expire(limitKey, int64(delaySeconds)) } if num.(int64) >= maxAttempts && blackSeconds > 0 {
// 加入黑名单 gredis.RawCommand("HSET", blackKey, item, time+blackSeconds) // 删除记录 gredis.RawCommand("HDEL", limitKey, item) } return true}// LUA脚本模式// 支持redis集群部署func luaScript(blackKey string, limitKey string, item string, time int64) (res bool) {
script := `local blackSeconds = tonumber(ARGV[5])if(blackSeconds > 0)then local timeout = redis.call('hget', KEYS[1], ARGV[1]) if(timeout ~= false) then if(tonumber(timeout) > tonumber(ARGV[2])) then return false end redis.call('hdel', KEYS[1], ARGV[1]) endendlocal last = redis.call('hget', KEYS[2], ARGV[1])if(last ~= false and tonumber(last) >= tonumber(ARGV[3]))then return falseendlocal num = redis.call('hincrby', KEYS[2], ARGV[1], 1)local ttl = redis.call('ttl', KEYS[2])if(ttl == -1)then redis.call('expire', KEYS[2], ARGV[4])endif(tonumber(num) >= tonumber(ARGV[3]) and blackSeconds > 0)then redis.call('hset', KEYS[1], ARGV[1], ARGV[2] + ARGV[5]) redis.call('hdel', KEYS[2], ARGV[1])endreturn true` result, err := gredis.RawCommand("EVAL", script, 2, blackKey, limitKey, item, time, maxAttempts, delaySeconds, blackSeconds) if err != nil {
return false } if result == int64(1) {
return true } else {
return false }}

转载地址:http://vcaui.baihongyu.com/

你可能感兴趣的文章
WAV文件解析
查看>>
DAC输出音乐2-解决pu pu 声
查看>>
WPF中PATH使用AI导出SVG的方法
查看>>
WPF UI&控件免费开源库
查看>>
QT打开项目提示no valid settings file could be found
查看>>
Win10+ESP32环境搭建正确姿势
查看>>
Win10+VSCode+ESP32环境搭建
查看>>
Win10+VS+ESP32环境搭建
查看>>
ESP32环境-每次都有新发现
查看>>
Ubuntu+win10远程桌面
查看>>
ESP32编译运行ADF音频库
查看>>
C++ 引用类型
查看>>
flutter-实现本地存储(sharePreference)
查看>>
flutter-实现圆角带边框的view(android无效)
查看>>
flutter-实现一个下拉刷新上拉加载的列表
查看>>
android 代码实现圆角
查看>>
postman调试webservice接口
查看>>
retrofit调试webservice(注意只是调试,没对结果进行处理)
查看>>
flutter-解析json
查看>>
android中shader的使用
查看>>