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版的更多相关文章
- Java中的参数验证(非Spring版)
1. Java中的参数验证(非Spring版) 1.1. 前言 为什么我总遇到这种非正常问题,我们知道很多时候我们的参数校验都是放在controller层的传入参数进行校验,我们常用的校验方式就是引入 ...
- 这是关于FastJson的一个使用Demo,在Java环境下验证的
public class User { private int id; private String name; public int getId() { return id; } public vo ...
- SpringMVC数据验证
SpringMVC数据验证——第七章 注解式控制器的数据验证.类型转换及格式化——跟着开涛学SpringMVC 资源来自:http://jinnianshilongnian.iteye.com/blo ...
- SpringMVC 使用验证框架 Bean Validation(上)
SpringMVC 使用验证框架 Bean Validation(上) 对于任何一个应用而言在客户端做的数据有效性验证都不是安全有效的,这时候就要求我们在开发的时候在服务端也对数据的有效性进行验证. ...
- Eclipse下创建Spring MVC web程序--非maven版
首先, 安装eclipse和tomcat, 这里我下载的是tomcat9.0版本64位免安装的:地址https://tomcat.apache.org/download-90.cgi 免安装的如何启动 ...
- 史上最全Java表单验证封装类
package com.tongrong.utils; import java.util.Collection; import java.util.Map; import java.util.rege ...
- Java的登陆验证问题
java中的登陆验证问题可以有多种方式进行验证,通过拦截器功能完成,可以通过过滤器功能完成,也可以简单的代码在JSP页面中单独完成,其中都 涉及到一个关键的验证步骤,这个验证原理ASP,PHP,JAV ...
- 购物车非cookie版
2015.11.26购物车,非cookie版 [点击来,你发现被骗了(笑哭,笑哭,笑哭,源代码的话,留下邮箱吧,是在不好找这一时半会儿的.)] Jsp通过反射机制获取bean中的标签,但其实,可以没有 ...
- 【IBM】Merlin 给 Java 平台带来了非阻塞 I/O
Merlin 给 Java 平台带来了非阻塞 I/O 新增的功能大幅降低了线程开销 Java 技术平台早就应该提供非阻塞 I/O 机制了.幸运的是,Merlin(JDK 1.4)有一根几乎在各个场合都 ...
随机推荐
- Environment中有大量访问目录的函数
public class Environment { /** * Return root of the "system" partition holding the core An ...
- 程序猿工具——svn
一个项目的产生,都需要团队中的开发人员互相协作.它的简单,方便深深吸引了我. svn的使用,有2部分组成--svn服务器.svn客户端.svn服务器一般团队之间只要有一个安装就可以了. 在学习安装sv ...
- 微软最新的Web服务器Katana发布了版本3
Katana 项目入门 Howard Dierking 当 ASP.NET 首次在 2002 年发布时,时代有所不同. 那时,Internet 仍处于起步阶段,大约有 5.69 亿用户,每个用户平均每 ...
- Python 设计模式--简单工厂模式
简单工厂模式(Factory Pattern)是一种创建型的设计模式,像工厂一样根据要求生产对象实例. 特点:根据不同的条件,工厂实例化出合适的对象. <大话设计模式>中实例:四则运算计算 ...
- 第一次阅读作业 xinzcover
---恢复内容开始--- 第一次阅读和准备作业 这个作业属于哪个课程 https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass1 这个作 ...
- Android ImageView setImageBitmap 不显示图片
从sd卡里读出图片后有时调用setImageBitmap(bitmap)方法会显示不出图片,仔细考虑过后原来是加载的图片过大导致的,解决办法为: BitmapFactory.Options op = ...
- Thinkphp3.23 连接MSSQL方法
Thinkphp 3.23要连接MSSQL,必须配置下,以下是主要的步骤. 1.要安装Microsoft Drivers for PHP for SQL Server驱动 下载驱动以前,要查看一下ph ...
- SharedPrefences的用处
存储数据 SharedPreferences.Editor edit = getSharedPreferences("data", MODE_PRIVATE).edit(); ed ...
- mysql 的 case when then 用法 和null 的判断
表:一个表 aa 有两个字段 id 和 sex ,第1条记录的sex 为空串 ('') 第二条记录的sex 为空 (null) 1. 用法: 第一种: select (case 字段名 whe ...
- chsh - 改变登录 shell
总览 (SYNOPSIS) chsh [ -s shell ] [ -l ] [ -u ] [ -v ] [ username ] 描述 (DESCRIPTION) chsh 用于 改变 用户的 登录 ...