iT邦幫忙

第 12 屆 iThome 鐵人賽

0
Modern Web

從coding到上線-打造自己的blog系統系列 第 31

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
	}

上一篇
Day30 總結
系列文
從coding到上線-打造自己的blog系統31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言