diff --git a/server/config.yaml b/server/config.yaml index 76d293eb..8a0ea966 100644 --- a/server/config.yaml +++ b/server/config.yaml @@ -44,6 +44,10 @@ system: db-type: 'mysql' oss-type: 'local' # 控制oss选择走本期还是 七牛等其他仓 自行增加其他oss仓可以在 server/utils/upload/upload.go 中 NewOss函数配置 use-multipoint: false + # IP限制次数 一个小时15000次 + iplimit-count: 15000 + # IP限制一个小时 + iplimit-time: 3600 # captcha configuration captcha: diff --git a/server/config/system.go b/server/config/system.go index 768788ab..8cf92b06 100644 --- a/server/config/system.go +++ b/server/config/system.go @@ -6,4 +6,6 @@ type System struct { DbType string `mapstructure:"db-type" json:"dbType" yaml:"db-type"` // 数据库类型:mysql(默认)|sqlite|sqlserver|postgresql OssType string `mapstructure:"oss-type" json:"ossType" yaml:"oss-type"` // Oss类型 UseMultipoint bool `mapstructure:"use-multipoint" json:"useMultipoint" yaml:"use-multipoint"` // 多点登录拦截 + LimitCountIP int `mapstructure:"iplimit-count" json:"iplimitCount" yaml:"iplimit-count"` + LimitTimeIP int `mapstructure:"iplimit-time" json:"iplimitTime" yaml:"iplimit-time"` } diff --git a/server/middleware/limit_ip.go b/server/middleware/limit_ip.go new file mode 100644 index 00000000..0e18cac9 --- /dev/null +++ b/server/middleware/limit_ip.go @@ -0,0 +1,54 @@ +package middleware + +import ( + "context" + "errors" + "github.com/flipped-aurora/gin-vue-admin/server/global" + "github.com/flipped-aurora/gin-vue-admin/server/model/common/response" + "github.com/gin-gonic/gin" + "time" +) + +// ip限制 +func IPLimit() gin.HandlerFunc { + return func(c *gin.Context) { + key := "RequestClientIPLimit===" + c.ClientIP() + limit := global.GVA_CONFIG.System.LimitCountIP + second := global.GVA_CONFIG.System.LimitTimeIP + expiration := time.Duration(second) * time.Second + if err := SetLimitWithTime(key, limit, expiration); err != nil { + response.FailWithMessage(err.Error(), c) + c.Abort() + return + } + // 继续往下处理 + c.Next() + } +} + +// 设置访问次数 +func SetLimitWithTime(key string, limit int, expiration time.Duration) error { + count, err := global.GVA_REDIS.Exists(context.Background(), key).Result() + if err != nil || count == 0 { + pipe := global.GVA_REDIS.TxPipeline() + pipe.Incr(context.Background(), key) + pipe.Expire(context.Background(), key, expiration) + _, err := pipe.Exec(context.Background()) + return err + } else { + //次数 + if times, err := global.GVA_REDIS.Get(context.Background(), key).Int(); err != nil { + return err + } else { + if times >= limit { + if t, err := global.GVA_REDIS.PTTL(context.Background(), key).Result(); err != nil { + return errors.New("请求太过频繁,请稍后再试") + } else { + return errors.New("请求太过频繁, 请 " + t.String() + " 秒后尝试") + } + } else { + return global.GVA_REDIS.Incr(context.Background(), key).Err() + } + } + } +}