RichCMS支持防止恶意抓取的功能,可以在站点配置->安全中去打开设置。本文章可以看到RichCMS中防止恶意抓取的功能的Go语言实现,以下是源代码部分:
文件:/common/sdk/rees/filter/filter.go
ackage filter
import (
"github.com/zituocn/gow"
"github.com/zituocn/richcms/common/repository/model"
"github.com/zituocn/richcms/common/repository/view"
)
// PluginExec 入口方法
func PluginExec(c *gow.Context, config *view.CrawlConfig) {
if config == nil {
return
}
ip := c.GetIP()
if ip != "" && !ipWhiteList.Exist(ip) {
// IP限流
IPLimiter(c, ip, config.Open, config.Second, config.Tokens)
// IP过滤
IPFilter(c, ip, config.Open)
}
}
func InitIPBox() {
data, _ := new(model.IPBox).GetIPBoxList()
InitIPBlackList(data)
InitIPWhiteList(data)
}
- PluginExec()函数,是一个入口函数,供RichCMS代码中的middleware部分调用。
- InitIPBox()函数,是在程序启动时调用,实现初始化。
文件: /common/sdk/rees/filter/ip_filter.go
package filter
import (
"github.com/zituocn/gow"
"github.com/zituocn/logx"
"github.com/zituocn/richcms/common/repository/enum"
"github.com/zituocn/richcms/common/repository/model"
"github.com/zituocn/richcms/common/sdk/rees/store"
)
var (
// ipBlackList 黑名单
ipBlackList *store.MemoryStore
// ipWhiteList 白名单
ipWhiteList *store.MemoryStore
)
// IPFilter ip过滤器
func IPFilter(c *gow.Context, ip string, open bool) {
if !open {
return
}
if ipBlackList.Exist(ip) {
ResponsePage(c)
}
}
func ResponsePage(c *gow.Context) {
c.String("禁止访问")
c.StopRun()
}
/*
白名单
*/
// InitIPWhiteList 初始化白名单IP
func InitIPWhiteList(data []*model.IPBox) {
ipWhiteList = new(store.MemoryStore)
i := 0
for _, item := range data {
if item.IP != "" && item.IPType == enum.WhiteIP {
i++
ipWhiteList.Store(item.IP)
}
}
logx.Infof("Load IP whitelist :%d", i)
}
/*
黑名单
*/
// InitIPBlackList 初始化黑名单IP
func InitIPBlackList(data []*model.IPBox) {
ipBlackList = new(store.MemoryStore)
i := 0
for _, item := range data {
if item.IP != "" && item.IPType == enum.BanIP {
i++
ipBlackList.Store(item.IP)
}
}
logx.Infof("Load IP blacklist :%d", i)
}
- 此文章是IP过滤器,当已经进入黑名单或白名单的IP地址,会做分别拦截和放行的处理。
- ResponsePage()函数的作用:当IP地址是黑名单时,向客户端响应“禁止访问”的信息。
文件:/common/sdk/rees/filter/ip_limiter.go
package filter
import (
"github.com/zituocn/gow"
"github.com/zituocn/gow/lib/limiter"
"github.com/zituocn/richcms/common/repository/enum"
"github.com/zituocn/richcms/common/repository/model"
"github.com/zituocn/richcms/common/utils"
"golang.org/x/time/rate"
"sync"
"time"
)
var (
// IP 限流
ipLimiter *limiter.IPLimiter
)
func newIPLimiter(r, b int) *limiter.IPLimiter {
return limiter.NewIPLimiter(rate.Every(time.Duration(r)*time.Second), b)
}
// IPLimiter IP限流器
func IPLimiter(c *gow.Context, ip string, open bool, second, tokens int) {
if !open {
return
}
if ipLimiter == nil {
ipLimiter = newIPLimiter(second, tokens)
}
limit := ipLimiter.GetLimiter(ip)
if !limit.Allow() {
banIP(ip)
ResponsePage(c)
}
}
// ReloadIPLimiter 重置 ipLimiter
func ReloadIPLimiter() {
mu := &sync.Mutex{}
mu.Lock()
ipLimiter = nil
mu.Unlock()
}
func banIP(v string) {
if v == "" {
return
}
ipBox := &model.IPBox{
IP: v,
IPType: enum.BanIP,
Created: utils.NowUnixTime(),
}
//写数据到DB
_ = ipBox.Create()
ipBlackList.Store(v)
}
- 此代码是IP限流器的实现,当达到配置的限量时,会进入黑名单。
在管理后台的工具菜单中,有“IP盒子”的功能,可以对白名单和进入系统的黑名单IP,进行管理。