(本文暂不讨论reCAPTCHA Android的使用方式,因为我也没用过XD)
1.申请reCAPTCHA API keys
想要使用reCAPTCHA,首先需要在reCAPTCHA控制台申请服务,并选择需要使用的API版本
其中,reCAPTCHA V2版需要用户选择一个复选框,Google将会在屏幕上呈现一些判断题,以验证用户是机器人还是人类
例如:
而reCAPTCHA Invisible则不需要用户选择复选框,可以直接集成在网页的提交按钮中,由Google根据用户的流量自动判断访问页面的是机器人还是人类
当Google发现可疑流量时,才会弹出与reCAPTCHA v2一样的验证码,此时,网页右下角会显示如下标志:
2.设置API
reCAPTCHA只会允许后台内设置的域名使用验证服务,否则会出现如下错误提示:
为了方便本地调试,建议在域名列表(Domains)中添加localhost与127.0.0.1
例如:
点击“Save changees”按钮,更新设置。
3.在页面中添加相应的控件
本部分以reCAPTCHA v2为例,整个验证的流程为:
(1)用户点击验证,前端页面获取到一个g-recaptcha-response值;
(2)将这个值发送到后端;
(3)后端再将Secret key、g-recaptcha-response、用户客户端ip(可选)一起发送到Google服务器;
(4)Google向后端返回是否验证成功;
(5)接入验证流程……
找到页面内的“Adding reCAPTCHA to your site”处,点击“Keys”,获取密钥
Site key需要放在前端页面中,而Secret key则需要放在后端,不能泄露
在网页头部添加如下js文件:
<script src='https://www.google.com/recaptcha/api.js'></script>
因为Google reCAPTCHA所在域名被墙,如果服务需要在国内访问,请替换为如下地址:
<script src="https://www.recaptcha.net/recaptcha/api.js"></script>
然后在页面中添加相应的控件:
<div class="g-recaptcha" data-sitekey="6LdSpUAUAAAAACpgcW_WPDqte35A0OLqwDm6KdwV" data-callback="flushStatus"></div>
其中,“data-sitekey”的值为申请到的Site key,“data-callback”为用户完成验证后调用的回调函数。
这样,我们就搭建出了一个基本的页面:
(注意!ajax.js仅为个人方便而调用的ajax轮子,可以替换为js原生方法或jQuery ajax)
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>reCAPTCHA v2 Demo</title> <script type="text/javascript" src="https://www.recaptcha.net/recaptcha/api.js"></script> <script type="text/javascript" src="js/ajax.js"></script> </head> <body> <div class="g-recaptcha" data-sitekey="6LdSpUAUAAAAACpgcW_WPDqte35A0OLqwDm6KdwV" data-callback="flushStatus"></div> <input type="button" value="submit" id="btn-submit" /> <br /> <p style="display:inline;color:red">验证状态: </p><span id="sp1"></span> <br /> <p style="display:inline;color:red">回调结果: </p><span id="sp2"></span> <br /> <p style="display:inline;color:red">取值结果: </p><span id="sp3"></span> <br /> <p style="display:inline;color:red">最终状态: </p><span id="sp4"></span> </body> </html>
(1)获取g-recaptcha-response
有两种方式可以获取到这个值:
1. 使用grecaptcha.getResponse()函数
2. 在data-callback中添加一个回调函数
比如:
function flushStatus(data) { document.getElementById("sp2").innerText = grecaptcha.getResponse();//直接取得g-recaptcha-response document.getElementById("sp3").innerText = data;//利用回调函数取得 }
此处可以看出,他们获取的结果是相同的。
(2)将这个值发送到后端
document.getElementById("btn-submit").onclick = function () { let verifyCode = grecaptcha.getResponse(); if (!verifyCode) {//如果g-recaptcha-response不为空 document.getElementById("sp1").innerText = "没有验证"; } else { document.getElementById("sp1").innerText = "已经验证"; let ajax = new Ajax(); ajax.send({ method: "POST", url: "/verify.ashx", resType: "json", data: { code: verifyCode//将g-recaptcha-response值传到后端 }, success: function (data) { document.getElementById("sp4").innerText = JSON.stringify(data); } }); } }
(3)后端验证
本文编写的是Asp.net一般处理程序(.ashx),并使用了Newtonsoft.Json框架来解析json数据,仅供参考
需要特别注意的是,向Google服务器提交数据时,虽然提交方式是POST,但必须像GET请求那样使用url参数(此处存疑?求dalao解答),否则会返回缺少参数的错误
(被这个坑了好久,md我的心好痛)
public class RequestData { public string secret; public string response; } public void ProcessRequest(HttpContext context) { RequestData requestData = new RequestData(); requestData.secret = "6LdSpUAUAAAAAKkS_4bojjF16mhzoPXXIsyZdN8j";//站点secret key requestData.response = context.Request.Form["code"];//客户端返回结果 if (requestData.response != "") { string postUrl = "https://recaptcha.net/recaptcha/api/siteverify?secret=" + requestData.secret + "&response=" + requestData.response; string postResult = HttpPost(postUrl);//发送 Debug.WriteLine(postResult); JObject jObject = JsonConvert.DeserializeObject(postResult) as JObject;//反序列化验证结果 if (jObject["success"].ToString().ToLower()=="true") { context.Response.ContentType = "application/json"; context.Response.Write("{\"status\":\"true\"}"); } else { context.Response.ContentType = "application/json"; context.Response.Write("{\"status\":\"false\"}"); } } else { context.Response.ContentType = "application/json"; context.Response.Write("{\"status\":\"false\"}"); } } public static string HttpPost(string url, string postDataStr = "")//模拟POST请求 { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Method = "POST"; request.ContentType = "application/json"; request.ContentLength = postDataStr.Length; StreamWriter writer = new StreamWriter(request.GetRequestStream(), Encoding.ASCII); writer.Write(postDataStr); writer.Flush(); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); string encoding = response.ContentEncoding; if (encoding == null || encoding.Length < 1) { encoding = "UTF-8"; } StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(encoding)); string retString = reader.ReadToEnd(); return retString; }
(4)Google返回的结果
这是一个验证成功的例子:
{ "success": true, "challenge_ts": "2018-02-10T10:31:22Z", "hostname": "localhost" }
这是一个验证失败的例子,失败的原因是缺少参数:
{ "success": false, "error-codes": [ "missing-input-response", "missing-input-secret" ] }
以下是Google官方对于error-codes的说明:
missing-input-secret secret参数丢失 invalid-input-secret secret参数无效或格式错误 missing-input-response response参数丢失 invalid-input-response response参数无效或格式错误 bad-request 请求无效或格式错误
(5)接入验证流程
单独地使用reCAPTCHA并没有什么用处,如果最终的判断仍在前端,那么该验证还是可以被篡改的。
一个建议的使用方式是,将g-recaptcha-response值参杂在提交的表单中。
5.总结
本文编写的reCAPTCHA v2完整例子,以及并未列出的reCAPTCHA Invisible例子,均已上传。
reCAPTCHA v2:https://github.com/KatyushaScarlet/reCAPTCHA-v2-Demo
reCAPTCHA Invisible:https://github.com/KatyushaScarlet/reCAPTCHA-Invisible-Demo