java springMVC 极致验证 非demo版

Posted yzw23333

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java springMVC 极致验证 非demo版相关的知识,希望对你有一定的参考价值。

最近公司项目需要,做了个极致验证,自己在此做下记录。

先上效果图:

技术分享图片

技术分享图片

技术分享图片

 

它的官网:http://www.geetest.com/   里面有 身份验证、行为验证,  我这使用的为行为验证。

技术文档:https://docs.geetest.com/install/overview/start/

 

接入前让产品经理在官网注册个账号,有免费版和付费版,免费版是500次/h,我这里用的是免费版。

注册好账号之后,新建一个模块,里面有你所需要的公钥(id)和私钥(key)。

好,开始部署服务端。

 

1.下载文档里的demo:https://github.com/GeeTeam/gt3-java-sdk/archive/master.zip。

 

2.\\WebContent目录下有个login.jsp,这是拖动滑块验证的页面,里面还有个gt.js,需要在你自己的页面中引入,具体好像是加快网络请求什么的吧,忘了。

\\src\\sdk目录下有个GeetestLib.java(该类封装了极验所有的方法,可以自己慢慢看),项目里直接导入进去即可。

demo下面src/demo/demo2是行为验证,里面三个java类,分别为

GeetestConfig.java实体类(封装着你的公钥和私钥)、

StartCaptchaServlet.java(GET请求,初始化滑动验证组件、页面用的)、

VerifyLoginServlet.java(POST请求,当你点击提交按钮时进入的方法,该方法做进一步验证,向极验服务器发送请求)。

 

3.聊聊jsp里面js部分:

<script>
var
handler2 = function (captchaObj) { $("#yes").click(function (e) { // 提交按钮id var phone = $("#phone").val(); //我的只要传电话号 做登录的需要传账号 密码 if(phone == ""){ //前台校验 $("#phoneError").html(" * 请输入手机号码"); return false; }else if(!/^(13[0-9]|14[0-9]|15[0-9]|17[0-9]|18[0-9])\\d{8}$/.test(phone)){ $("#phoneError").html(" * 请输入正确的手机号码"); return false; }else{ $("#phoneError").html(""); // 先校验是否点击了验证码 var result = captchaObj.getValidate(); if (!result) { $("#error").html(" * 请先点击验证码"); return false; } else {
          // 前端校验通过后,进入后台检验极致验证: $.ajax({ url:
‘VerifyLoginServlet.java里面POST方法路径‘, type: ‘POST‘, dataType: ‘json‘, data: { telephone : $("#phone").val(), // 我的传手机号 登录的要传 账号密码 geetest_challenge: result.geetest_challenge, // 该方法里必需的三个参数 geetest_validate: result.geetest_validate, geetest_seccode: result.geetest_seccode }, success: function (data) { $("#phoneError").html(""); // 清空前端校验提示 if (data.status == ‘success‘) { //后端方法成功传回的参数值为success $("#phoneError").html(""); //号码存到cookie,下一个页面取值 cookie(名字,值,有效期:天) // 我下一个页面要取手机号 所以存在cookie里了,用cookie记得引用cookie的js文件 $.cookie(‘phone‘, phone, { expires: 1 }); $.cookie(‘boole‘, ‘1‘); // 我做校验用的cookie window.location = ‘${pageContext.request.contextPath}/verification‘; // 校验成功跳到下个页面 } else if (data.status == ‘fail‘) { $("#error").html(" * 验证失败"); } } }) } e.preventDefault(); } }); // 将验证码加到id为captcha的元素里,同时会有1个input的值用于表单提交 我这是手机号,是1个, 登录的有2个 captchaObj.appendTo("#captcha2"); captchaObj.onReady(function () { $("#wait2").hide(); }); };
//页面加载先调用这个ajax $.ajax({ url:
"StartCaptchaServlet.java类里面GET方法的路径?t=" + (new Date()).getTime(), // 加随机数防止缓存 我的路径为:${pageContext.request.contextPath}/startCaptchaAPI1?t=" + (new Date()).getTime() type: "get", dataType: "json", success: function (data) { // 调用 initGeetest 初始化参数 // 参数1:配置参数 // 参数2:回调,回调的第一个参数验证码对象,之后可以使用它调用相应的接口 initGeetest({ gt: data.gt, challenge: data.challenge, new_captcha: data.new_captcha, // 用于宕机时表示是新验证码的宕机 offline: !data.success, // 表示用户后台检测极验服务器是否宕机,一般不需要关注 product: "popup", // 产品形式,包括:float,popup width: "100%" }, handler2); // 调用handler2,在js开始的部分 } });
</script>
 

 

4.聊聊 GeetestLib.java类中方法(太多的方法,只说其中几个自己用的看的):

/**
* 极验验证二次验证表单数据 chllenge
*/
public static final String fn_geetest_challenge = "geetest_challenge";

/**
* 极验验证二次验证表单数据 validate
*/
public static final String fn_geetest_validate = "geetest_validate";

/**
* 极验验证二次验证表单数据 seccode
*/
public static final String fn_geetest_seccode = "geetest_seccode";

/**
* 公钥
*/
private String captchaId = "";

/**
* 私钥
*/
private String privateKey = "";

 

/**
     * 服务正常的情况下使用的验证方式,向gt-server进行二次验证,获取验证结果
     * 
     * @param challenge
     * @param validate
     * @param seccode
     * @return 验证结果,1表示验证成功0表示验证失败
     */
    public int enhencedValidateRequest(String challenge, String validate, String seccode, HashMap<String, String> data) {    
        
        if (!resquestIsLegal(challenge, validate, seccode)) {
            
            return 0;
            
        }
        
        gtlog("request legitimate");
        
        String userId = data.get("user_id");
        String clientType = data.get("client_type");
        String ipAddress = data.get("ip_address");
        
        String postUrl = this.apiUrl + this.validateUrl;
        String param = String.format("challenge=%s&validate=%s&seccode=%s&json_format=%s", 
                                     challenge, validate, seccode, this.json_format);
        
        if (userId != null){
            param = param + "&user_id=" + userId;
        }
        if (clientType != null){
            param = param + "&client_type=" + clientType;
        }
        if (ipAddress != null){
            param = param + "&ip_address=" + ipAddress;
        }
        
        gtlog("param:" + param);
        
        String response = "";
        try {
            
            if (validate.length() <= 0) {
                
                return 0;
                
            }

            if (!checkResultByPrivate(challenge, validate)) {
                
                return 0;
                
            }
            
            gtlog("checkResultByPrivate");
            
            response = readContentFromPost(postUrl, param);      //这个方法自己可以断点看,里面很详细

            gtlog("response: " + response);    //  发给极验服务器的响应数据  会返回一个{"scode":""}
            
        } catch (Exception e) {
            
            e.printStackTrace();
            
        }
        
        String return_seccode = "";
        
        try {
            
            JSONObject return_map = new JSONObject(response);
            return_seccode = return_map.getString("seccode");
            gtlog("md5: " + md5Encode(return_seccode));              // 返回的响应数据经过md5加密 输出

            if (return_seccode.equals(md5Encode(seccode))) {
                
                return 1;  //1 验证成功  0 失败
                
            } else {
                
                return 0;
                
            }
            
        } catch (JSONException e) {
            
        
            gtlog("json load error");
            return 0;
            
        }
        
    }

 

/**
     * 发送GET请求,获取服务器返回结果
     * 
     * @param getURL
     * @return 服务器返回结果
     * @throws IOException
     */
    private String readContentFromGet(String URL) throws IOException {

        URL getUrl = new URL(URL);
        HttpURLConnection connection = (HttpURLConnection) getUrl
                .openConnection();

        connection.setConnectTimeout(2000);// 设置连接主机超时(单位:毫秒)
        connection.setReadTimeout(2000);// 设置从主机读取数据超时(单位:毫秒)

        // 建立与服务器的连接,并未发送数据
        connection.connect();
        
        if (connection.getResponseCode() == 200) {
            // 发送数据到服务器并使用Reader读取返回的数据
            StringBuffer sBuffer = new StringBuffer();

            InputStream inStream = null;
            byte[] buf = new byte[1024];
            inStream = connection.getInputStream();
            for (int n; (n = inStream.read(buf)) != -1;) {
                sBuffer.append(new String(buf, 0, n, "UTF-8"));
            }
            inStream.close();
            connection.disconnect();// 断开连接
            
            return sBuffer.toString();    
        }
        else {
            
            return "fail";
        }
    }

 

/**
     * 发送POST请求,获取服务器返回结果
     * 
     * @param getURL
     * @return 服务器返回结果
     * @throws IOException
     */
    private String readContentFromPost(String URL, String data) throws IOException {
        
        gtlog(data);
        URL postUrl = new URL(URL);
        HttpURLConnection connection = (HttpURLConnection) postUrl
                .openConnection();

        connection.setConnectTimeout(2000);// 设置连接主机超时(单位:毫秒)
        connection.setReadTimeout(2000);// 设置从主机读取数据超时(单位:毫秒)
        connection.setRequestMethod("POST");
        connection.setDoInput(true);
        connection.setDoOutput(true);
        connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        
        // 建立与服务器的连接,并未发送数据
        connection.connect();
        
         OutputStreamWriter outputStreamWriter = new OutputStreamWriter(connection.getOutputStream(), "utf-8");  
         outputStreamWriter.write(data);  
         outputStreamWriter.flush();
         outputStreamWriter.close();
        
        if (connection.getResponseCode() == 200) {
            // 发送数据到服务器并使用Reader读取返回的数据
            StringBuffer sBuffer = new StringBuffer();

            InputStream inStream = null;
            byte[] buf = new byte[1024];
            inStream = connection.getInputStream();
            for (int n; (n = inStream.read(buf)) != -1;) {
                sBuffer.append(new String(buf, 0, n, "UTF-8"));
            }
            inStream.close();
            connection.disconnect();// 断开连接
            
            return sBuffer.toString();    
        }
        else {
            
            return "fail";
        }
    }

 

5.聊聊 StartCaptchaServlet.java类中方法:

/**
     * 极验 第一次验证 API1
     * 初始化结果标识status(status=1表示初始化成功,status=0表示宕机状态)需要用户保存,在后续二次验证时会取出并进行逻辑判断。用session来存取status。
     * @return
     * @throws IOException 
     */
    @RequestMapping(value = "/startCaptchaAPI1", method = RequestMethod.GET)
    @ResponseBody
    public void startCaptchaAPI1(HttpServletRequest request, HttpServletResponse response) throws IOException{
        //该方法提供正常模式下验证和宕机模式下验证
        String captchaId = "官网里面自己取";   //公钥
        String privateKey = "官网里面自己取";     //私钥
        boolean failback = true;   //是否开启failback模式    (开不开启宕机)
        GeetestLib gtSdk = new GeetestLib(captchaId, privateKey, failback);  //实例化GeetestLib
        String resStr = "{}";
        //极验服务器区分的标识
        String userid = "test";   //这里根据自己需要,判断的一个条件  可选择添加  我这里直接写死的 值为test
        
        //自定义参数,可选择添加
        HashMap<String, String> param = new HashMap<String, String>();
        param.put("user_id", userid); //网站用户id
        param.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);   //调用GeetestLib里的预处理方法  1成功 0失败
        //将服务器状态设置到session中
        final Subject subject = SecurityUtils.getSubject();
        final Session session = subject.getSession();
        session.setAttribute(gtSdk.gtServerStatusSessionKey, gtServerStatus);     //后面第二步会拿这些参数
        //将userid设置到session中
        session.setAttribute("userid", userid);
        
        resStr = gtSdk.getResponseStr();       //获取本次验证初始化返回字符串
        PrintWriter out = response.getWriter();
        out.println(resStr);
        out.close();
    }

 

6.聊聊VerifyLoginServlet.java类中方法:

/**
     * 极验 第二次验证 API2
     * 
     * @return
     * @throws IOException 
     */
    @RequestMapping(value = "/VerifyLoginAPI2", method = RequestMethod.POST)
    @ResponseBody
    public void VerifyLoginAPI2(HttpServletRequest request, HttpServletResponse response) throws IOException{
        String captchaId = "官网自己取";   //公钥
        String privateKey = "官网自己取";     //私钥
        boolean failback = true;   //是否开启failback模式
        GeetestLib gtSdk = new GeetestLib(captchaId, privateKey, failback);
        
        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中获取userid
        String userid = (String)request.getSession().getAttribute("userid");
        
        //自定义参数,可选择添加
        HashMap<String, String> param = new HashMap<String, String>(); 
        param.put("user_id", userid); //网站用户id
        param.put("client_type", "web"); //web:电脑上的浏览器;h5:手机上的浏览器,包括移动应用内完全内置的web_view;native:通过原生SDK植入APP应用的方式
        param.put("ip_address", "127.0.0.1"); //传输用户请求验证时所携带的IP
        
        int gtResult = 0;
        if (gt_server_status_code == 1) {
            //gt-server正常,向gt-server进行二次验证
            gtResult = gtSdk.enhencedValidateRequest(challenge, validate, seccode, param);   //向gt-server进行二次验证,获取验证结果
        } else {
            // gt-server非正常情况下,进行failback模式验证
            gtResult = gtSdk.failbackValidateRequest(challenge, validate, seccode);
        }
        
        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());
            out.close();
        }
        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());
            out.close();
        }
    }

 




以上是关于java springMVC 极致验证 非demo版的主要内容,如果未能解决你的问题,请参考以下文章

SpringMVC 验证:找不到属性“commandClass”

SpringMVC的JSR303数据验证

怎么用springmvc处理form表单的ajax验证

Spring功能介绍SpringMVC集成Java Bean Validation实现参数检验功

springmvc的特点

SpringMVC服务器端校验-无配置文件