想不到以前的草稿還能拿出來寫。
最近將代碼重構了,看情況回頭修以前文章的bug(機率不大
reCAPTCHA是google推出的我不是機器人服務,可以幫忙過濾一些機器人的流量,這邊以V3版本為例,google會根據使用者的一些行為判斷使用者有多像機器人,而不需要讓使用者花時間去點圖形。
先到reCAPTCHA官網申請帳號,在網域的地方輸入自己的網域,有趣的是,如果想在本地測試,輸入127.0.0.1也可以使用。
之後會得到兩組金鑰,一組是用於前端,另一組則是要放在自己server上不能隨意公開的
根據官方文件的描述,可以直接將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
}