1.controller
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>后台管理-登陆</title> <link rel="stylesheet" href="layui/css/layui.css"> <link rel="stylesheet" href="images/login.css"> <style> .admin-header{ text-align: center; font-size: 28px; font-family: '微软雅黑'; font-weight: 100; } .a-button{ width:300px; margin-top:10px; } body{ background-image: url(images/bj.jpg); background-repeat: no-repeat; background-size:100% 100%; background-attachment:fixed; } </style> </head> <body> <div id="container"> <div></div> <div class="admin-login-background"> <div class="admin-header"> 苏州工业园区市政服务集团档案管理系统 </div> <form class="layui-form" method="post" action="${pageContext.request.contextPath}/login.do"> <div> <i class="layui-icon layui-icon-username admin-icon admin-icon-username"></i> <input type="text" name="username" placeholder="请输入用户名" id="username" autocomplete="off" class="layui-input admin-input admin-input-username"> </div> <div> <i class="layui-icon layui-icon-password admin-icon admin-icon-password"></i> <input type="password" name="password" id="password" placeholder="请输入密码" autocomplete="off" class="layui-input admin-input"> </div> <div> <div id="captcha2"> <p id="wait2" class="show">正在加载验证码......</p> </div> </div> <br> <a id="submit2" class="layui-btn a-button" href="javascript:void(0);" >登陆</a> </form> </div> </div> <script src="layui/layui.js"></script> <script src="images/jquery.js"></script> <script src="images/gt.js"></script> <script> var cnt = 0; var handler2 = function (captchaObj) { $("#submit2").click(function (e) { var result = captchaObj.getValidate(); if (!result) {//代表没有去验证 // $("#notice2").show(); // setTimeout(function () { // $("#notice2").hide(); // }, 2000); layui.use(['layer', 'form'], function(){ layer.open({ title: '提示信息' ,content: '您还未验证请先验证!' }); }); } else {//页面已经验证,进入登陆方法 cnt++; alert("验证完成"); var username=$("#username").val(); var password=$("#password").val(); if(username==null || username==""){//判断用户名是否输入 alert("用户名不能为空"); return false; } if(password==null || password==""){//判断密码是否输入 alert("密码不能为空"); return false; } if(cnt == 1){ $.ajax({//进入二次验证 url: 'login.do', type: 'POST', dataType: 'json', data: { "username": username, "password": password, "geetest_challenge": result.geetest_challenge, "geetest_validate": result.geetest_validate, "geetest_seccode": result.geetest_seccode }, success: function (data) { alert(data+"data"); if(data == "3"){ layui.use(['layer','form'],function(){ layer.open({ title:'提示消息' ,content:'验证错误!' }); }); return false; }else if(data == "2"){ layui.use(['layer','form'],function(){ layer.open({ title:'提示消息' ,content:'您输入的账号或者密码错误!' }); }); return false; } alert("登陆成功") //登录成功,跳转项目后台 <%-- window.location.href="${pageContext.request.contextpath}/ ";--%> } }); }else{ $.ajax({//进入二次验证 url: 'login2.do', type: 'POST', dataType: 'json', data: { "username": username, "password": password }, success: function (data) { alert(data+"data"); if(data == "2"){ layui.use(['layer','form'],function(){ layer.open({ title:'提示消息' ,content:'您输入的账号或者密码错误!' }); }); return false; } alert("登陆成功") //登录成功,跳转项目后台 <%-- window.location.href="${pageContext.request.contextpath}/ ";--%> } }); } } e.preventDefault(); }); // 将验证码加到id为captcha的元素里,同时会有三个input的值用于表单提交 captchaObj.appendTo("#captcha2"); captchaObj.onReady(function () { $("#wait2").hide(); }); // 更多接口参考:http://www.geetest.com/install/sections/idx-client-sdk.html }; $.ajax({ url: "startCaptcha2.do?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%" // 更多配置参数请参见:http://www.geetest.com/install/sections/idx-client-sdk.html#config }, handler2); } }); </script> <script> //用户登陆方法login(); function login(){ var username=$("#username").val(); var password=$("#password").val(); if(username==null || username==""){//判断用户名是否输入 alert("用户名不能为空"); return false; } if(password==null || password==""){//判断密码是否输入 alert("密码不能为空"); return false; } $.ajax({ url:"${pageContext.request.contextPath}/login/login4.action", type:"POST", data:{"username":username,"password":password}, dataType:"json", success:function(data){ if(data=="2"){ layui.use(['layer', 'form'], function(){ layer.open({ title: '提示信息' ,content: '您输入的账号或者密码错误!' }); }); updateVerify(); return false; } window.location.href="${pageContext.request.contextPath}/user/returnIndex.action"; } }) } </script> </body> </html>
2.验证官方代码
package com.tanzhou.tzms.common.HKverify; import org.springframework.stereotype.Component; /** * GeetestWeb配置文件 * * */ @Component public class GeetestConfig { // 填入自己的captcha_id和private_key private static final String geetest_id = "48a6ebac4ebc6642d68c217fca33eb4d"; private static final String geetest_key = "4f1c085290bec5afdc54df73535fc361"; private static final boolean newfailback = true; public static final String getGeetest_id() { return geetest_id; } public static final String getGeetest_key() { return geetest_key; } public static final boolean isnewfailback() { return newfailback; } } package com.tanzhou.tzms.common.HKverify; import java.awt.print.Printable; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.lang.reflect.GenericArrayType; import java.net.HttpURLConnection; import java.net.InetAddress; import java.net.Socket; import java.net.URL; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.logging.Logger; import javax.print.DocFlavor.STRING; import javax.servlet.descriptor.JspConfigDescriptor; import javax.servlet.http.HttpServletRequest; import javax.xml.crypto.Data; import org.json.JSONException; import org.json.JSONObject; import org.springframework.stereotype.Component; /** * Java SDK * */ @Component public class GeetestLib { protected final String verName = "4.0"; protected final String sdkLang = "java"; protected final String apiUrl = "http://api.geetest.com"; protected final String registerUrl = "/register.php"; protected final String validateUrl = "/validate.php"; protected final String json_format = "1"; /** * 极验验证二次验证表单数据 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 = ""; /** * 是否开启新的failback */ private boolean newFailback = false; /** * 返回字符串 */ private String responseStr = ""; /** * 调试开关,是否输出调试日志 */ public boolean debugCode = true; /** * 极验验证API服务状态Session Key */ public String gtServerStatusSessionKey = "gt_server_status"; /** * 带参数构造函数 * * @param captchaId * @param privateKey */ public GeetestLib(String captchaId, String privateKey, boolean newFailback) { this.captchaId = captchaId; this.privateKey = privateKey; this.newFailback = newFailback; } /** * 获取本次验证初始化返回字符串 * * @return 初始化结果 */ public String getResponseStr() { return responseStr; } public String getVersionInfo() { return verName; } /** * 预处理失败后的返回格式串 * * @return */ private String getFailPreProcessRes() { Long rnd1 = Math.round(Math.random() * 100); Long rnd2 = Math.round(Math.random() * 100); String md5Str1 = md5Encode(rnd1 + ""); String md5Str2 = md5Encode(rnd2 + ""); String challenge = md5Str1 + md5Str2.substring(0, 2); JSONObject jsonObject = new JSONObject(); try { jsonObject.put("success", 0); jsonObject.put("gt", this.captchaId); jsonObject.put("challenge", challenge); jsonObject.put("new_captcha", this.newFailback); } catch (JSONException e) { gtlog("json dumps error"); } return jsonObject.toString(); } /** * 预处理成功后的标准串 * */ private String getSuccessPreProcessRes(String challenge) { gtlog("challenge:" + challenge); JSONObject jsonObject = new JSONObject(); try { jsonObject.put("success", 1); jsonObject.put("gt", this.captchaId); jsonObject.put("challenge", challenge); } catch (JSONException e) { gtlog("json dumps error"); } return jsonObject.toString(); } /** * 验证初始化预处理 * * @return 1表示初始化成功,0表示初始化失败 */ public int preProcess(HashMap<String, String> data) { if (registerChallenge(data) != 1) { this.responseStr = this.getFailPreProcessRes(); return 0; } return 1; } /** * 用captchaID进行注册,更新challenge * * @return 1表示注册成功,0表示注册失败 */ private int registerChallenge(HashMap<String, String>data) { try { String userId = data.get("user_id"); String clientType = data.get("client_type"); String ipAddress = data.get("ip_address"); String getUrl = apiUrl + registerUrl + "?"; String param = "gt=" + this.captchaId + "&json_format=" + 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("GET_URL:" + getUrl + param); String result_str = readContentFromGet(getUrl + param); if (result_str == "fail"){ gtlog("gtServer register challenge failed"); return 0; } gtlog("result:" + result_str); JSONObject jsonObject = new JSONObject(result_str); String return_challenge = jsonObject.getString("challenge"); gtlog("return_challenge:" + return_challenge); if (return_challenge.length() == 32) { this.responseStr = this.getSuccessPreProcessRes(this.md5Encode(return_challenge + this.privateKey)); return 1; } else { gtlog("gtServer register challenge error"); return 0; } } catch (Exception e) { gtlog(e.toString()); gtlog("exception:register api"); } return 0; } /** * 判断一个表单对象值是否为空 * * @param gtObj * @return */ protected boolean objIsEmpty(Object gtObj) { if (gtObj == null) { return true; } if (gtObj.toString().trim().length() == 0) { return true; } return false; } /** * 检查客户端的请求是否合法,三个只要有一个为空,则判断不合法 * * @param request * @return */ private boolean resquestIsLegal(String challenge, String validate, String seccode) { if (objIsEmpty(challenge)) { return false; } if (objIsEmpty(validate)) { return false; } if (objIsEmpty(seccode)) { return false; } return true; } /** * 服务正常的情况下使用的验证方式,向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); } 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)); if (return_seccode.equals(md5Encode(seccode))) { return 1; } else { return 0; } } catch (JSONException e) { gtlog("json load error"); return 0; } } /** * failback使用的验证方式 * * @param challenge * @param validate * @param seccode * @return 验证结果,1表示验证成功0表示验证失败 */ public int failbackValidateRequest(String challenge, String validate, String seccode) { gtlog("in failback validate"); if (!resquestIsLegal(challenge, validate, seccode)) { return 0; } gtlog("request legitimate"); return 1; } /** * 输出debug信息,需要开启debugCode * * @param message */ public void gtlog(String message) { if (debugCode) { System.out.println("gtlog: " + message); } } protected boolean checkResultByPrivate(String challenge, String validate) { String encodeStr = md5Encode(privateKey + "geetest" + challenge); return validate.equals(encodeStr); } /** * 发送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"; } } /** * md5 加密 * * @time 2014年7月10日 下午3:30:01 * @param plainText * @return */ private String md5Encode(String plainText) { String re_md5 = new String(); try { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(plainText.getBytes()); byte b[] = md.digest(); int i; StringBuffer buf = new StringBuffer(""); for (int offset = 0; offset < b.length; offset++) { i = b[offset]; if (i < 0) i += 256; if (i < 16) buf.append("0"); buf.append(Integer.toHexString(i)); } re_md5 = buf.toString(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return re_md5; } } package com.tanzhou.tzms.common.HKverify; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; /** * 使用Get的方式返回challenge和capthca_id,此方式以实现前后端完全分离的开发模式 * */ @Controller public class StartCaptchaServlet2{ @RequestMapping("/startCaptcha2") public void startCaptcha2(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { GeetestLib gtSdk = new GeetestLib(GeetestConfig.getGeetest_id(), GeetestConfig.getGeetest_key(), GeetestConfig.isnewfailback()); String resStr = "{}"; //自定义userid String userid = "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); //将服务器状态设置到session中 request.getSession().setAttribute(gtSdk.gtServerStatusSessionKey, gtServerStatus); //将userid设置到session中 request.getSession().setAttribute("userid", userid); resStr = gtSdk.getResponseStr(); PrintWriter out = response.getWriter(); out.println(resStr); } }
3.jsp登陆页面
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>后台管理-登陆</title> <link rel="stylesheet" href="layui/css/layui.css"> <link rel="stylesheet" href="images/login.css"> <style> .admin-header{ text-align: center; font-size: 28px; font-family: '微软雅黑'; font-weight: 100; } .a-button{ width:300px; margin-top:10px; } body{ background-image: url(images/bj.jpg); background-repeat: no-repeat; background-size:100% 100%; background-attachment:fixed; } </style> </head> <body> <div id="container"> <div></div> <div class="admin-login-background"> <div class="admin-header"> 苏州工业园区市政服务集团档案管理系统 </div> <form class="layui-form" method="post" action="${pageContext.request.contextPath}/login.do"> <div> <i class="layui-icon layui-icon-username admin-icon admin-icon-username"></i> <input type="text" name="username" placeholder="请输入用户名" id="username" autocomplete="off" class="layui-input admin-input admin-input-username"> </div> <div> <i class="layui-icon layui-icon-password admin-icon admin-icon-password"></i> <input type="password" name="password" id="password" placeholder="请输入密码" autocomplete="off" class="layui-input admin-input"> </div> <div> <div id="captcha2"> <p id="wait2" class="show">正在加载验证码......</p> </div> </div> <br> <a id="submit2" class="layui-btn a-button" href="javascript:void(0);" >登陆</a> </form> </div> </div> <script src="layui/layui.js"></script> <script src="images/jquery.js"></script> <script src="images/gt.js"></script> <script> var cnt = 0; var handler2 = function (captchaObj) { $("#submit2").click(function (e) { var result = captchaObj.getValidate(); if (!result) {//代表没有去验证 // $("#notice2").show(); // setTimeout(function () { // $("#notice2").hide(); // }, 2000); layui.use(['layer', 'form'], function(){ layer.open({ title: '提示信息' ,content: '您还未验证请先验证!' }); }); } else {//页面已经验证,进入登陆方法 cnt++; alert("验证完成"); var username=$("#username").val(); var password=$("#password").val(); if(username==null || username==""){//判断用户名是否输入 alert("用户名不能为空"); return false; } if(password==null || password==""){//判断密码是否输入 alert("密码不能为空"); return false; } if(cnt == 1){ $.ajax({//进入二次验证 url: 'login.do', type: 'POST', dataType: 'json', data: { "username": username, "password": password, "geetest_challenge": result.geetest_challenge, "geetest_validate": result.geetest_validate, "geetest_seccode": result.geetest_seccode }, success: function (data) { alert(data+"data"); if(data == "3"){ layui.use(['layer','form'],function(){ layer.open({ title:'提示消息' ,content:'验证错误!' }); }); return false; }else if(data == "2"){ layui.use(['layer','form'],function(){ layer.open({ title:'提示消息' ,content:'您输入的账号或者密码错误!' }); }); return false; } alert("登陆成功") //登录成功,跳转项目后台 <%-- window.location.href="${pageContext.request.contextpath}/ ";--%> } }); }else{ $.ajax({//进入二次验证 url: 'login2.do', type: 'POST', dataType: 'json', data: { "username": username, "password": password }, success: function (data) { alert(data+"data"); if(data == "2"){ layui.use(['layer','form'],function(){ layer.open({ title:'提示消息' ,content:'您输入的账号或者密码错误!' }); }); return false; } alert("登陆成功") //登录成功,跳转项目后台 <%-- window.location.href="${pageContext.request.contextpath}/ ";--%> } }); } } e.preventDefault(); }); // 将验证码加到id为captcha的元素里,同时会有三个input的值用于表单提交 captchaObj.appendTo("#captcha2"); captchaObj.onReady(function () { $("#wait2").hide(); }); // 更多接口参考:http://www.geetest.com/install/sections/idx-client-sdk.html }; $.ajax({ url: "startCaptcha2.do?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%" // 更多配置参数请参见:http://www.geetest.com/install/sections/idx-client-sdk.html#config }, handler2); } }); </script> <script> //用户登陆方法login(); function login(){ var username=$("#username").val(); var password=$("#password").val(); if(username==null || username==""){//判断用户名是否输入 alert("用户名不能为空"); return false; } if(password==null || password==""){//判断密码是否输入 alert("密码不能为空"); return false; } $.ajax({ url:"${pageContext.request.contextPath}/login/login4.action", type:"POST", data:{"username":username,"password":password}, dataType:"json", success:function(data){ if(data=="2"){ layui.use(['layer', 'form'], function(){ layer.open({ title: '提示信息' ,content: '您输入的账号或者密码错误!' }); }); updateVerify(); return false; } window.location.href="${pageContext.request.contextPath}/user/returnIndex.action"; } }) } </script> </body> </html>