1. 程式人生 > >java springMVC 極致驗證 非demo版

java springMVC 極致驗證 非demo版

產品 ddr 行為 pan src config 100% ecc post方法

最近公司項目需要,做了個極致驗證,自己在此做下記錄。

先上效果圖:

技術分享圖片

技術分享圖片

技術分享圖片

它的官網: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版