本文最后更新于 2021年04月13日 已经是 898天前了 ,文章可能具有时效性,若有错误或已失效,请在下方留言。
Google 验证码接入
前言
为了区分访问者是否为机器人,我们常添加验证码来达到此目的。这里我们使用Google的reCaptchaV3和reCaptchaV2结合来做认证。同时也可以起到CSRF防御的功能!
申请令牌
谷歌官网 需要某些特殊方法才能访问哟
配置前端
这里我们前端使用的是VUE
# 前期我们需要把V2的验证方法给隐藏起来,使用V3来验证更方便
import reCaptcha from '../layouts/google.vue'
...
login: async function () {
const csrf = getCookie('csrf')
const _this = this
if (csrf !== '') {
if (this.username === '' || this.password === '') {
this.isError = true
this.errorInfo = '用户名或密码你没填呢!'
} else {
if (this.token === '' && this.googleV3) {
this.isError = true
this.errorInfo = '验证码你没有填写呢!'
return
}
this.visible = true
const v3token = await this.GetV3Token()
console.log(v3token)
this.$axios.post('api/login', {
username: this.username,
password: this.$md5(this.password),
csrfToken: csrf,
google: this.token,
rememberMe: this.rememberMe,
googleV3: v3token
}).then(function (response) {
if (response.data.code === 1) {
_this.$q.notify({
type: 'positive',
position: 'top',
message: response.data.info,
icon: 'fa fa-check'
})
_this.Jump(1)
} else if (response.data.code === 3) {
_this.isError = true
_this.googleV3 = true
_this.errorInfo = response.data.info
_this.passwordErr = false
} else {
_this.isError = true
_this.errorInfo = response.data.info
_this.passwordErr = true
}
}).catch(function (error) {
_this.isError = true
_this.errorInfo = error.message
_this.passwordErr = false
}).finally(function () {
_this.visible = false
})
}
} else {
this.isError = true
this.errorInfo = 'CSRF令牌获取失败, 无法登录!'
this.passwordErr = false
}
},
# 获取v3的token函数
GetV3Token: async function () {
let returnToken = ''
await this.$recaptcha('login').then((token) => {
returnToken = token
})
console.log('tokenV3 ' + returnToken)
return returnToken
}
},
...
后端
app.Post("api/login", func(ctx iris.Context) {
username := ctx.FormValue("username")
password := ctx.FormValue("password")
//rememberMe := ctx.FormValue("rememberMe")
token := ctx.FormValue("google")
tokenV3 := ctx.FormValue("googleV3")
// "记住我"功能未实现!
if username != "" && password != "" {
if token == "" {
if !methods.VerifyGoogleV3(tokenV3) {
_, _ = ctx.JSON(methods.ReturnPack{Code: 3, Info: "检测到你可能是机器人,请输入验证码!"})
return
}
} else {
if !methods.VerifyGoogleV2(token) {
_, _ = ctx.JSON(methods.ReturnPack{Code: 0, Info: "验证码验证出现问题!"})
return
}
}
user, err := methods.VerifyUsernamePassword(username, password, ctx.RemoteAddr())
if err == nil {
if user.Role == -1 {
_, _ = ctx.JSON(methods.ReturnPack{Code: 0, Info: "账号已被封禁, 请联系网站管理员!"})
return
}
if user.SessId != "" {
sysinit.Sess.DestroyByID(user.SessId)
}
s := sysinit.Sess.Start(ctx)
s.Set("auth", true)
s.Set("id", user.Id)
s.Set("role", user.Role)
s.Set("username", user.Username)
_ = methods.SetSessId(user, s.ID())
//log.Info(rememberMe)
_, _ = ctx.JSON(methods.ReturnPack{Code: 1, Info: "登录成功,欢迎你" + user.Username + "正在为你跳转!"})
} else {
_, _ = ctx.JSON(methods.ReturnPack{Code: 0, Info: err.Error()})
}
} else {
_, _ = ctx.JSON(methods.ReturnPack{Code: 0, Info: "你未填写用户名或密码"})
}
})
相关验证函数
// 验证谷歌验证码V2
func VerifyGoogleV2(token string) bool {
res, err := requests.Get("https://recaptcha.net/recaptcha/api/siteverify", requests.Params{"secret": config.Sysconfig.RecaptchaSecretV2, "response": token})
if err != nil {
log.Error(err.Error())
return false
}
log.Info(res.Text())
var googleBack GoogleBack
err = res.Json(&googleBack)
if err != nil {
log.Error(err.Error())
return false
}
return googleBack.Success
}
// 验证谷歌验证码V3
func VerifyGoogleV3(token string) bool {
res, err := requests.Get("https://recaptcha.net/recaptcha/api/siteverify", requests.Params{"secret": config.Sysconfig.RecaptchaSecretV3, "response": token})
if err != nil {
log.Error(err.Error())
return false
}
log.Info(res.Text())
var googleBackV3 GoogleBackV3
err = res.Json(&googleBackV3)
if err != nil {
log.Error(err.Error())
return false
}
if googleBackV3.Score > 0.5 {
return true
} else {
return false
}
}
结果
[+] [信息] [2021-03-05 10:38:12]: {
"success": true,
"challenge_ts": "2021-03-05T02:32:06Z",
"hostname": "localhost",
"score": 0.9,
"action": "login"
}
此时我们就可以做到在v3验证失败的情况下调起v2来辅助验证!
验证码功能成功实现.