业务场景
在系统业务中,需要想客户发送手机验证码,进行验证后,才能提交。但为了防止不正当的短信发送(攻击,恶意操作等),需要在发送短信前添加一个行为验证(这里使用的是 极验);
参考文档:
极验行为验证文档:https://docs.geetest.com/install/overview/start/
极验demo:https://www.geetest.com/demo/
步骤:
这里参考下 官方流程,前面的注册验证就不说了,直接重点
搭建geetest的后台
首先从Github: gt3-python-sdk下载.zip
文件 ,用于后台搭建
- gt3-java-sdk-master\src\sdk\GeetestLib.java 这个文件相当java中的实体类,直接放在我的domain文件下。
- gt3-java-sdk-master\src\demo\demo1\GeetestConfig.java ,是geetest的配置文件,用来放我们在极验后台注册应用得到的captcha_id和private_key。
- VerifyLoginServlet.java(验证) 和 StartCaptchaServlet.java(初始化),这两个文件就是两个servlet,我直接放到了我写的一个Controller里面;
import com.jhly.common.config.GeetestConfig;
import com.jhly.common.domain.GeetestLib;
import org.activiti.engine.impl.util.json.JSONException;
import org.activiti.engine.impl.util.json.JSONObject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;@Controller
@RequestMapping("/gt")
public class GeetestController {/*** 初始化极验** @param request* @param geetestDto* @param random 防止缓存* @return*/@GetMapping("/register")@ResponseBodyprotected void register(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {GeetestLib gtSdk = new GeetestLib(GeetestConfig.getGeetest_id(), GeetestConfig.getGeetest_key(),GeetestConfig.isnewfailback());String resStr = "{}";String userid = "test";//自定义参数,可选择添加HashMap<String, String> param = new HashMap<String, String>();param.put("user_id", userid); //网站用户idparam.put("client_type", "web"); //web:电脑上的浏览器;h5:手机上的浏览器,包括移动应用内完全内置的web_view;native:通过原生SDK植入APP应用的方式param.put("ip_address", "127.0.0.1"); //传输用户请求验证时所携带的IP//进行验证预处理int gtServerStatus = gtSdk.preProcess(param);//将服务器状态设置到session中request.getSession().setAttribute(gtSdk.gtServerStatusSessionKey, gtServerStatus);//将userid设置到session中request.getSession().setAttribute("userid", userid);resStr = gtSdk.getResponseStr();PrintWriter out = response.getWriter();out.println(resStr);}/*** 使用post方式,返回验证结果, request表单中必须包含challenge, validate, seccode*/@PostMapping("/validate")@ResponseBodyprotected void validate(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {GeetestLib gtSdk = new GeetestLib(GeetestConfig.getGeetest_id(), GeetestConfig.getGeetest_key(),GeetestConfig.isnewfailback());String challenge = request.getParameter(GeetestLib.fn_geetest_challenge);String validate = request.getParameter(GeetestLib.fn_geetest_validate);String seccode = request.getParameter(GeetestLib.fn_geetest_seccode);//从session中获取gt-server状态int gt_server_status_code = (Integer) request.getSession().getAttribute(gtSdk.gtServerStatusSessionKey);//从session中获取useridString userid = (String)request.getSession().getAttribute("userid");//自定义参数,可选择添加HashMap<String, String> param = new HashMap<String, String>();param.put("user_id", userid); //网站用户idparam.put("client_type", "web"); //web:电脑上的浏览器;h5:手机上的浏览器,包括移动应用内完全内置的web_view;native:通过原生SDK植入APP应用的方式param.put("ip_address", "127.0.0.1"); //传输用户请求验证时所携带的IPint gtResult = 0;if (gt_server_status_code == 1) {//gt-server正常,向gt-server进行二次验证gtResult = gtSdk.enhencedValidateRequest(challenge, validate, seccode, param);System.out.println(gtResult);} else {// gt-server非正常情况下,进行failback模式验证System.out.println("failback:use your own server captcha validate");gtResult = gtSdk.failbackValidateRequest(challenge, validate, seccode);System.out.println(gtResult);}if (gtResult == 1) {// 验证成功PrintWriter out = response.getWriter();JSONObject data = new JSONObject();try {data.put("status", "success");data.put("version", gtSdk.getVersionInfo());} catch (JSONException e) {e.printStackTrace();}out.println(data.toString());}else {// 验证失败JSONObject data = new JSONObject();try {data.put("status", "fail");data.put("version", gtSdk.getVersionInfo());} catch (JSONException e) {e.printStackTrace();}PrintWriter out = response.getWriter();out.println(data.toString());}}}
待建geetest的前端
需要用到gt.js
我这里用的是 geetest 的bind类型。效果:https://www.geetest.com/demo/slide-bind.html
引入gt.js
<script src="gt.js"></script>
搭建容器,我是bind的一个btn
JavaScript
<script>var handler = function (captchaObj) {captchaObj.onReady(function () {$("#wait").hide();}).onSuccess(function () {var result = captchaObj.getValidate();if (!result) {return alert('请完成验证');}$.ajax({url: '/gt/validate',type: 'POST',dataType: 'json',data: {username: $('#username2').val(),password: $('#password2').val(),geetest_challenge: result.geetest_challenge,geetest_validate: result.geetest_validate,geetest_seccode: result.geetest_seccode},success: function (data) {if (data.status === 'success') {setTimeout(function () {//完成后发送验证码sendsms()// alert('登录成功');}, 1500);} else if (data.status === 'fail') {setTimeout(function () {alert('登录失败,请完成验证');captchaObj.reset();}, 1500);}}});});$("#hqyzm").click(function () {var phone = $('#bnzf-phone').val(); //获取输入的手机号码// $.Dialog.loading();var reg_phone = /^0?(13[0-9]|15[012356789]|18[0123456789]|14[57]|17[678]|170[059]|14[57]|166|19[89])[0-9]{8}$/;;if(!reg_phone.test(phone)){ //验证手机是否符合格式layer.msg("手机号格式不正确");return false;}// 调用之前先通过前端表单校验captchaObj.verify();})};$.ajax({url: "/gt/register?t=" + (new Date()).getTime(), // 加随机数防止缓存type: "get",dataType: "json",success: function (data) {// 调用 initGeetest 进行初始化// 参数1:配置参数// 参数2:回调,回调的第一个参数验证码对象,之后可以使用它调用相应的接口initGeetest({// 以下 4 个配置参数为必须,不能缺少gt: data.gt,challenge: data.challenge,offline: !data.success, // 表示用户后台检测极验服务器是否宕机new_captcha: data.new_captcha, // 用于宕机时表示是新验证码的宕机product: "bind", // 产品形式,包括:float,popupwidth: "300px",https: true}, handler);}});
</script>
效果: