【集成】极验验证
极验验证地址
http://www.geetest.com
极验验证用途
防止用户恶意频繁请求服务器,也就是防刷,主要用于安全认证。
看官方文档你会发现,其实就是通过弹出验证码窗口进行验证拦截,根据验证结果你可进行自己的操作。
极验验证的使用集成
此处在官方文档有说明,详情点击http://docs.geetest.com/install/client/android/,此处不做赘述。
在此主要说出集成极验验证时的一些坑,以及处理方案。
基本说明:需要服务器提供两个接口 初始化配置接口/验证接口
进入源码你会发现sdk通过
new GT3GeetestUrl().setCaptchaURL(captchaURL);
new GT3GeetestUrl().setValidateURL(validateURL);
将初始化接口/验证接口进行了保存(请自行查看源码),之后通过
gt3GeetestUtils.getGeetest();
进行开始验证,在此通过执行task来对之前配置的两个接口发起网络请求,那么问题来了
1.如何在请求中插入cookie
/**
* 验证回调
*/
private static class GTListener implements GT3GeetestUtils.GT3Listener {
private Map<String, String> data = new HashMap<>();
// dialog关闭
@Override
public void gt3CloseDialog() {
isCloseFlag = true;
}
// 点击其他,关闭dialog
@Override
public void gt3CancelDialog() {
isCloseFlag = true;
}
// 验证码加载准备完成
@Override
public void gt3DialogReady() {
EvtLog.e("validate", "gt3DialogReady");
}
// 首次请求返回结果,将getCode拿到的两个数据,在发送验证的时候带回去
// 因为sdk不支持添加cookie,所以用此方法来通知后台是否为同一用户
@Override
public void gt3FirstResult(JSONObject jsonObject) {
try {
data.put("captcha_uid", jsonObject.getString("captcha_uid"));
data.put("status", jsonObject.getString("status"));
} catch (JSONException e) {
e.printStackTrace();
}
}
// 二次请求返回结果
@Override
public Map<String, String> gt3SecondResult() {
return data;
}
@Override
public void gt3GetDialogResult(String result) {
}
// 验证码 验证成功
@Override
public void gt3DialogSuccess() {
isCloseFlag = true;
}
// 验证码 验证失败
@Override
public void gt3DialogOnError() {
isCloseFlag = true;
}
@Override
public void gt3DialogSuccessResult(String result) {
}
@Override
public Map<String, String> captchaHeaders() {
// 此方法只是将cookie相关数据加到header并没有加到cookie,依然会造成后台生成新的seesionid
// 处理方案,后台返回一个唯一标识,在验证时返回 回去
// LZCookieStore cookieStore = new LZCookieStore(FeizaoApp.mConctext);
// List<Cookie> cookies = cookieStore.getCookies();
// Map<String, String> data = new HashMap<>();
// if (cookies != null) {
// for (Cookie cookie :
// cookies) {
// data.put(cookie.getName(), cookie.getValue());
// }
// }
// return data;
return null;
}
}
在sdk提供的回调中captchaHeaders()是给 初始化配置接口请求时添加header,但是并未单独放入cookie下面,所以需要自己解析。
但实际应用场景一般会在cookie下面放入一些参数用于判断是否为同一用户下的请求,所以在这里有两个解决方案
1. 后台在此接口上做特殊判断,在header中直接去拿,我们通过captchaHeaders()将参数放入header;
2. 我们初始化请求时服务器返回一个参数作为唯一标识,在验证validate的接口时,将此参数值带入到请求body中。
在此段代码中,也就是我当前的项目中使用的是第二种方式进行的处理
2.如何避免谈起多个dialog
sdk通过geetestUtils.getGeetest();
来开启验证的,那么我们看一下它的源码
public void getGeetest() {
getLight = GT3LifecycleCallBacks.getInstance(context).gt3SendMsg();
GT3LifecycleCallBacks.getInstance(context).clearAllMsg();
senMsg = new GT3AroundMsg(context).gt3SendSenMsg();
new GT3AroundMsg(context).endSensor();
mGtAppDlgTask = new GtAppDlgTask();
mGtAppDlgTask.execute();
if (!((Activity) context).isFinishing()) {
dialog = new GT3GtDialog(context);
Window dialogWindow = dialog.getWindow();
WindowManager.LayoutParams lp = dialogWindow.getAttributes();
dialogWindow.setGravity(Gravity.CENTER);
dialogWindow.setAttributes(lp);
dialog.show();
dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialo) {
gtListener.gt3CancelDialog();
}
});
dialog.setGtListener(new GT3GtDialog.GtListener() {
@Override
public void gtResult(boolean success, String result) {
gtListener.gt3GetDialogResult(result);
if (success) {
mGtAppValidateTask = new GtAppValidateTask();
mGtAppValidateTask.execute(result);
} else {
//TODO 验证失败
dialog.shakeDialog();
}
}
@Override
public void success() {
gtListener.gt3DialogSuccess();
}
@Override
public void gtCallReady(Boolean status) {
if (status) {
//TODO 验证加载完成
gtListener.gt3DialogReady();
} else {
//TODO 验证加载超时,未准备完成
}
}
@Override
public void gtCallClose() {
gtListener.gt3CloseDialog();
}
@Override
public void gtError() {
gtListener.gt3DialogOnError();
}
});
}
captcha.setTimeout(5000);
captcha.setGeetestListener(new GT3Geetest.GeetestListener() {
@Override
public void readContentTimeout() {
mGtAppDlgTask.cancel(true);
//TODO 获取验证参数超时
//Looper.prepare() & Looper.loop(): 在当前线程并没有绑定Looper时返回为null, 可以与toastMsg()一同在正式版本移除
Looper.prepare();
// toastMsg("read content time out");
Looper.loop();
}
@Override
public void submitPostDataTimeout() {
mGtAppValidateTask.cancel(true);
//TODO 提交二次验证超时
// toastMsg("submit error");
}
@Override
public void receiveInvalidParameters() {
//TODO 从API接收到无效的JSON参数
// toastMsg("Did recieve invalid parameters.");
}
});
}
观察源码你会发现,
1. 只要当前activity未停止,只要你调用此方法就会打开新的dialog,并且sdk未提供dialog手动销毁的方法。所以在此你会遇到的问题是:当你请求多个接口并且都需要验证时,它会谈起多个对话框,影响用户体验。在此我做了一个处理,代码如下:
package packagename.common;
import android.app.Activity;
import com.efeizao.feizao.library.util.EvtLog;
import com.example.sdk.GT3GeetestUtils;
import org.json.JSONException;
import org.json.JSONObject;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
/**
* Created by Elvis on 2017/6/21.
* description : 使用极验验证请求,操作是否频繁,存在自动刷请求
*/
public class GTValidateRequest {
private static GT3GeetestUtils geetestUtils = null;
private static GTValidateRequest gtValidateRequest = null;
private static boolean isCloseFlag = true; //如果dialog被关闭则为true,否则为false
public static GTValidateRequest getInstance() {
if (gtValidateRequest == null) {
gtValidateRequest = new GTValidateRequest();
}
return gtValidateRequest;
}
/**
* @param context 上下文activity,用于第三方sdk使用(第三方仅支持activity作为上下文对象)
*/
public void validate(WeakReference<Activity> context) {
EvtLog.e("validate", "activity:" + context.get().getComponentName().getClassName());
// dialog已经关闭
if (isCloseFlag) {
isCloseFlag = false;
if (geetestUtils == null) {
geetestUtils = new GT3GeetestUtils(context.get());
}
geetestUtils.setGtListener(new GTListener());
geetestUtils.getGeetest();
}
}
/**
* 验证回调
*/
private static class GTListener implements GT3GeetestUtils.GT3Listener {
private Map<String, String> data = new HashMap<>();
// dialog关闭
@Override
public void gt3CloseDialog() {
isCloseFlag = true;
}
// 点击其他,关闭dialog
@Override
public void gt3CancelDialog() {
isCloseFlag = true;
}
// 验证码加载准备完成
@Override
public void gt3DialogReady() {
EvtLog.e("validate", "gt3DialogReady");
}
// 首次请求返回结果,将getCode拿到的两个数据,在发送验证的时候带回去
// 因为sdk不支持添加cookie,所以用此方法来通知后台是否为同一用户
@Override
public void gt3FirstResult(JSONObject jsonObject) {
try {
data.put("captcha_uid", jsonObject.getString("captcha_uid"));
data.put("status", jsonObject.getString("status"));
} catch (JSONException e) {
e.printStackTrace();
}
}
// 二次请求返回结果
@Override
public Map<String, String> gt3SecondResult() {
return data;
}
@Override
public void gt3GetDialogResult(String result) {
}
// 验证码 验证成功
@Override
public void gt3DialogSuccess() {
isCloseFlag = true;
}
// 验证码 验证失败
@Override
public void gt3DialogOnError() {
isCloseFlag = true;
}
@Override
public void gt3DialogSuccessResult(String result) {
}
@Override
public Map<String, String> captchaHeaders() {
// 此方法只是将cookie相关数据加到header并没有加到cookie,依然会造成后台生成新的seesionid
// 处理方案,后台返回一个唯一标识,在验证时返回 回去
// LZCookieStore cookieStore = new LZCookieStore(FeizaoApp.mConctext);
// List<Cookie> cookies = cookieStore.getCookies();
// Map<String, String> data = new HashMap<>();
// if (cookies != null) {
// for (Cookie cookie :
// cookies) {
// data.put(cookie.getName(), cookie.getValue());
// }
// }
// return data;
return null;
}
}
}
在代码中我添加了一个boolean作为标识,用来判断dialog是否被关闭。
默认为关闭,也就是默认允许弹出dialog,当弹出后,状态设置为false,说明已经打开dialog;然后在它的监听中设置状态,gt3CloseDialog()/gt3CancelDialog()/gt3DialogSuccess()/gt3DialogOnError(),这几中情况dialog都会被关闭,我们在此将状态设置为true。这样就可以用来避免dialog的多次打开。(此方案之适用于之前dialog依赖的activity已经销毁。当activity销毁时,dialog也会销毁。如果存在未销毁情况,你只需要在此方案上加入activity是否为同一个的判断就好)。
3. 初始化GT3GeetestUtils
看源码(片段2)中你会发现,他在验证时使用上下文,将其强制转换为activity,所以这里,在初始化时必须传入的是 Activity,那么问题来了,很多时候我们不会直接将其放到activity去调用,更多的是写为一个工具类,在公共的比如网络请求的地方去调用,那么这个时候我们如何获取activity对象呢,在此我直列出代码,在全局保存一个activity来进行随时使用
/**
* 获取栈顶activity
* 通过注册activity的生命周期监听获取最新的栈顶activity
*/
private static WeakReference<Activity> app_activity;
private void initGlobeActivity() {
getApplication().registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
app_activity = new WeakReference<>(activity);
Log.e("onActivityCreated===", app_activity + "");
}
@Override
public void onActivityDestroyed(Activity activity) {
}
/** Unused implementation **/
@Override
public void onActivityStarted(Activity activity) {
app_activity = new WeakReference<>(activity);
}
@Override
public void onActivityResumed(Activity activity) {
app_activity = new WeakReference<>(activity);
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
});
}
在此我们就拿到了栈顶的activity,记得一定要用弱引用。
结束语
在此极验验证的集成问题已经介绍完了,如果有什么疑问可以博客留言或者发送邮件到elvis@guojiang.tv。
如果觉得可以帮到你那么就拉倒底部,赞一个。
实现方式已粘贴到博客,所以在此就不下发下载链接了。
- 上一篇: 极验与vue的原生js结合
- 下一篇: 学习网站