极验有一款行为验证的插件,其实就是个验证码插件,包括滑块和点选的验证方式,这里记录一下如何接入基于 Vue + SpringBoot 的 Web 端项目
git clone https://github.com/GeeTeam/gt3-java-sdk.git
直接下载geetest_id
和 geetest_key
修改成自己的即可
doGet
演示初始化,doPost
演示接收验证请求private HashMap<String, String> getParams() {
String clientIp = URIUtil.getClientIp(request);
HashMap<String, String> params = Maps.newHashMap();
params.put("user_id", clientIp);
params.put("client_type", "web");
params.put("ip_address", clientIp);
return params;
}
getParams()
获取参数就是上一个函数public String generateCaptcha() {
// 初始化极验服务
GeetestLib lib = new GeetestLib(GeetestConfig.getGeetest_id(), GeetestConfig.getGeetest_key(), GeetestConfig.isnewfailback());
// 验证预处理
int status = lib.preProcess(getParams());
// 将服务状态存放到 Session 中,在第二步验证时会用到
request.getSession().setAttribute(lib.gtServerStatusSessionKey, status);
// 返回生成字串
return lib.getResponseStr();
}
request.getParameter()
可以直接使用,是因为我的 Service 集成了一个通用的父类,在里面直接注入了 HttpServletRequest
request
获取的参数都不是自定义的,由极验前端的 gt.js 内部提供saveMessage()
是验证成功后将当前参与验证的手机号和结果存储到 Redis 中,时效 5 分钟
TSharkException()
是自定义的异常处理,由 Controller 捕获后抛到前端弹出提示框告知用户public void checkCaptcha(String mobile) {
// 初始化极验服务
GeetestLib lib = new GeetestLib(GeetestConfig.getGeetest_id(), GeetestConfig.getGeetest_key(), GeetestConfig.isnewfailback());
// 接收前端参数,由前端 JS 内部封装处理
String challenge = request.getParameter(GeetestLib.fn_geetest_challenge);
String validate = request.getParameter(GeetestLib.fn_geetest_validate);
String seccode = request.getParameter(GeetestLib.fn_geetest_seccode);
// 取出第一步初始化验证时存储的服务状态
int status = (Integer) request.getSession().getAttribute(lib.gtServerStatusSessionKey);
int result = 0;
if (status == 1) {
// 服务器在线
result = lib.enhencedValidateRequest(challenge, validate, seccode, getParams());
} else {
// 服务器离线
result = lib.failbackValidateRequest(challenge, validate, seccode);
}
if (result == 1) {
// 保存验证信息
saveMessage(mobile, new MessageBean(mobile, result));
} else {
throw new TSharkException("行为验证失败,请检查使用环境");
}
}
@RestController
、@GetMapping
以及 @PostMapping
来区分请求SimpleActionHandler
是自定义封装的 Service 异常处理类
request
在继承的 AbstractBaseController
自定义父类中统一声明ResponseData
是自定义封装的返回结果类@Api("行为验证")
@RestController
@RequestMapping("/api/captcha")
public class CaptchaController extends AbstractBaseController {
@Autowired
private CaptchaServiceImpl captchaService;
@ApiOperation("生成行为验证")
@GetMapping("")
public ResponseData init() {
return new SimpleActionHandler(request) {
@Override
public void doAction(ResponseData responseData) throws Exception {
responseData.setData(captchaService.generateCaptcha());
}
}.handle();
}
@ApiOperation("进行行为验证")
@PostMapping("")
public ResponseData check(@RequestParam final String mobile) {
return new SimpleActionHandler(request) {
@Override
public void doAction(ResponseData responseData) throws Exception {
captchaService.checkCaptcha(mobile);
}
}.handle();
}
}
<script type="text/ecmascript-6">
import 'assets/plugins/geetest/gt'
export default { ... }
</script>
mt-cell
是 MINT UI 的组件<mt-cell class="captcha-wrapper">
<div class="captcha register-captcha">div>
mt-cell>
className
是行为验证所处的容器obj
和 objCheck
是注册或忘记密码时填写的信息内容也内容验证状态export default {
mounted () {
this._initGeeTest('register-captcha', this.register, this.rstate)
},
methods: {
// 初始化行为验证
_initGeeTest (className, obj, objCheck) {
// 清空之前的历史
this.captchaStatus = false
document.getElementsByClassName(className)[0].innerHTML = ''
this.$fetch.captcha.generate().then((res) => {
let result = JSON.parse(res.data)
window.initGeetest({
gt: result.gt,
challenge: result.challenge,
new_captcha: result.new_captcha,
offline: !result.success,
product: 'float',
width: '100%'
}, (captchaObj) => {
captchaObj.appendTo(`.${className}`)
captchaObj.onSuccess(() => {
// 手机号验证
if (!this._mobileCheck(obj, objCheck)) {
captchaObj.reset()
return false
}
let result = captchaObj.getValidate()
this.$fetch.captcha.check({
mobile: obj.username,
geetest_challenge: result.geetest_challenge,
geetest_validate: result.geetest_validate,
geetest_seccode: result.geetest_seccode
}).then((res) => {
if (!res.success) {
this.captchaStatus = false
this.$toast.error(res.data)
captchaObj.reset()
} else {
this.captchaStatus = true
}
})
})
})
})
}
}
}