Day31 使用reCAPTCHA过滤robot

前言

想不到以前的草稿还能拿出来写。

最近将代码重构了,看情况回头修以前文章的bug(机率不大

reCAPTCHA是google推出的我不是机器人服务,可以帮忙过滤一些机器人的流量,这边以V3版本为例,google会根据使用者的一些行为判断使用者有多像机器人,而不需要让使用者花时间去点图形。

准备

先到reCAPTCHA官网申请帐号,在网域的地方输入自己的网域,有趣的是,如果想在本地测试,输入127.0.0.1也可以使用。

https://ithelp.ithome.com.tw/upload/images/20220126/20124291deIYJhAq0H.png

之後会得到两组金钥,一组是用於前端,另一组则是要放在自己server上不能随意公开的

https://ithelp.ithome.com.tw/upload/images/20220126/20124291uOUhaAz3U0.png

使用

根据官方文件的描述,可以直接将reCAPTCHA绑订在一个按钮上,但这方法较没有弹性,所以使用下面一种方法。

假设我们希望发出登陆请求的使用者不是机器人,打开sign.js,将登入的地方改写

let reCAPTCHA_token = "6LcCuJwdAAAAAI2ITaq_01Xobie7X2FK9hTLuEvP";

$("#SignForm").submit(function(e) {

    let url = $(this).attr('action');
    let username = $("#InputUserName").val();
    let password = $("#InputPassword").val();
    let data = new FormData();
    data.append('username', username);
    data.append('password', password);

    grecaptcha.ready(function() {
        grecaptcha.execute(reCAPTCHA_token, {action: 'submit'}).then(function(token) {
            // Add your logic to submit to your backend server here.
            data.append('response', token);
            $.ajax({
                method: "POST",
                url: url,
                data: data,
                processData: false,
                contentType: false,
                xhrFields: {
                    withCredentials: true
                },
                success: function(data){
                    console.log(data)
                    SetUserCookie(data.user)
                    window.location.reload();
                },
                error: function(jqXHR, textStatus, errorThrown){
                    console.log(jqXHR)
                    console.log(textStatus)
                    console.log(errorThrown)
                    $("#AlertWrongParam").show();
                }
            });
        });
    });

    e.preventDefault(); // avoid to execute the actual submit of the form.
});

解释:
当按下送出表单後,会先把请求发给google检查是否是机器人,google会回应一组token,接着将这组token跟使用者的资料送到後台处理

後台要将这笔token送给google来确定这位使用者的分数,这过程还需要我们的另一组金钥来认证

在middleware/auth.go补上

func CheckRobot() gin.HandlerFunc {
	return func(c *gin.Context) {
		serve.CheckRobot(c)
		if c.IsAborted() {
			return
		}

		c.Next()
	}
}

之後可以在router package选择想要检查是否是机器人的路径上接上这个middleware

在serve/auth.go补上

// check request is by robot
func CheckRobot(c *gin.Context) {
	resp, err := http.PostForm("https://www.google.com/recaptcha/api/siteverify",
		url.Values{
			"secret":   {"your key"},
			"response": {c.PostForm("response")},
			"remoteip": {c.ClientIP()},
		},
	)
}

发送请求给google,接着处理google的回应,取得google判断的分数,在CheckRobot内补上


	if err != nil {
		log.Warn(c, apperr.ErrPermissionDenied, err, "Sorry, something error", "error in sent post request to reCAPTCHA")
		c.Abort()
		return
	}
	var res map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&res)
	// parse google response
	if val, ok := res["success"].(bool); !ok {
		err := errors.New("wrong error type")
		log.Error(c, apperr.ErrSystemFail, err, 0, "Sorry, something error", "assert wrong type")
		c.Abort()
		return
	} else if !val {
		err := errors.New("wrong argument")
		log.Warn(c, apperr.ErrWrongArgument, err, "Sorry, something error", "wrong response token")
		c.Abort()
		return
	}

有了分数就能以此来决定怎麽做了,这边的处理逻辑是直接无视掉太像机器人(分数小於自订的score值)的请求,在CheckRobot内补上。

	// compare score
	score, err := strconv.ParseFloat(setting.Servers["main"].ReCAPTCHA["AcceptScore"], 64)
	if err != nil {
		log.Warn(c, apperr.ErrWrongArgument, err, "Sorry, something error", "parse config string to float fail")
		c.Abort()
		return
	}
	if val, ok := res["score"].(float64); !ok {
		err = errors.New("wrong error type")
		log.Error(c, apperr.ErrSystemFail, err, 0, "Sorry, something error", "assert wrong type")
		c.Abort()
		return
	} else if val < score {
		err := errors.New("robot denied")
		log.Warn(c, apperr.ErrWrongArgument, err, "Sorry, we don't accept robot", "robot denied")
		c.Abort()
		return
	}

<<:  [Python]回归模型01─运用OLS做回归

>>:  因边界网关协议 ( BGP) 路由配置错误导致 DNS 故障而遭受服务中断,防止此事件的最佳对策-对配置更改实施两人控制

Day 19:非 GUI 类工具之 juce::String

前几篇重点放在 JUCE GUI 相关工具,接下来换个口味,介绍几个 JUCE 提供的好用组件。首先...

IOS Swift 简写Closure,我也能做到吗?

前言: 本来要睡了但感觉今天过得太废了所以惩罚自己再打一篇,明天要去自己最喜欢的导演开设的酒吧参加活...

萤幕录影和笔电录音-- Windows 7/8

新版本的 Windows 作业系统,但是不少用户还是喜欢用经典的 Windows 7/8 版本。我们...

[DAY 20] Model 训练技巧

前言 历经千辛万苦,那我们在train Model 时,总会发现有时效果不好,可能Training ...

Day4-Go Go Go!第一只 golang!

Hello rookie! 在经过昨天安装完环境後,相信大家已经迫不及待要写第一支程序了吧。 相信大...