这篇文章主要介绍了vue项目中极验验证的使用代码示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
使用vue、react的项目获取数据、上传数据、注册、登陆等都是通过接口来完成的,接口很容易被人恶意调用,最容易被人恶意调用的接口就是注册、登陆类的接口,为了防止接口被恶意调用很多公司开发了出了很多的人机验证的工具,今天就来讲下极验验证在vue项目中的使用。

效果预览

1、遇到的问题

    在项目中任何一个页面或vue组件都有可能需要使用到极验,并且极验在初始化时需要传递一些参数,要怎么做才能做到每一个组件都能很方便的使用极验呢? 极验应该在什么时候初始化?是组件一加载就初始化还是用户点击按钮后再初始化? 在多语言项目中,用户手动切换语言后的极验重置

2、代码分享

为了在多个页面或多个组件中都能方便的使用极验,我将极验初始化的相关代码写到了mixins中。这样做的好处是:方便在组件中获取极验相关的数据,以及调用极验相关api,如做重置、销毁等操作;缺点是:在同一个页面中无法在多个地方使用mixin,但这也是有解决方案的。

geetest-mixin.js

/*
 极验mixin
 */
// 导入极验官方给的代码
import gt from "../common/js/geetest/geetest.gt";
import {commonApi} from "../api/commonApi";
import {mapGetters} from "vuex";
// 自定义语言与极验语言对应表
const geetestLangMap = {
 "zh_CN": "zh-cn",
 "zh_TW": "zh-tw",
 "en_US": "en",
 "ja_JP": "ja",
 "ko_KR": "ko",
 "ru_RU": "ru"
};
console.log('gt',gt)
// 极验默认配置
const geetestOptions = {
 product: 'popup', // 极验展现形式 可选值有 float、popup、custom、bind
 width: '100%',
 lang: 'zh_CN',
 autoShow: true, // 当product为bind时,如果次参数为true,则在极验加载完成后立即显示极验弹窗
 area: null, // 极验绑定的元素,仅在 product为 custom、float、popup时需要传递
 autoRefreshOnLangChange: true, // 语言改变时是否自动刷新
};
export const geetestMixin = {
 data(){
  return {
   geetest: {
    geetestSuccessData: null, // 极验用户行为操作成功后的数据
    geetestObj: null, // 极验对象
    geetestLoading: false,
    geetestFatched: false, // 判断是否从服务器获取了极验数据
    showGeetest: false, // 是否使用极验
    sign: "", // 极验降级 用的签名
    geetestRestartCountMax: 5, // 极验重试最大此时
    count: 1,
    geetestOptions: {}
   }
  }
 },
 computed: {
  ...mapGetters(['get_lang'])
 },
 watch: {
  get_lang(lang){
   let options = this.geetest.geetestOptions;
   if(options.autoRefreshOnLangChange && this.geetest.geetestObj){
    this.initGeetest({
     ...options,
     lang: lang.code
    });
   }
  }
 },
 methods: {
  // 初始化极验
  initGeetest(options){
   if(!options || ({}).toString.call(options) !== '[object Object]'){
    console.error('initGeetest方法的参数options必须是一个对象!');
    return;
   }
   let newOptions = Object.assign({}, geetestOptions, options);
   if((newOptions.product === 'popup' || newOptions.product === 'custom' || newOptions.product === 'float') && !newOptions.area){
    console.error('product为popup、custom、float时options参数中必须有area属性,area属性值可以为css选择器或dom元素!');
    return;
   }
   this.geetest.geetestOptions = newOptions;
   this._geetestRegist_(newOptions);
  },
  // 重置极验
  geetestReset(cb){
   if(this.geetest.geetestObj){
    this.geetest.geetestSuccessData = {};
    this.geetest.geetestObj.reset();
    if(typeof cb === 'function'){
     cb();
    }
   }else{
    console.error('极验不存在!');
   }
  },
  // 显示极验弹窗,此方法只有在product为bind时才有效
  geetestShow(){
   if(this.geetest.geetestObj){
    if(this.geetest.geetestOptions.product === 'bind'){
     this.geetest.geetestObj.verify();
    }else{
     console.error('极验的product值非bind,无法调用show!');
    }
   }else{
    console.error('极验不存在!');
   }
  },
  // 初始化极验,内部使用
  _initGeetestInternal_(data, options){
   let that = this;
   let geetest = this.geetest;

   window.initGeetest({
    // 以下 4 个配置参数为必须,不能缺少
    gt: data.gt,
    challenge: data.challenge,
    offline: !data.success, // 表示用户后台检测极验服务器是否宕机
    new_captcha: true, // 用于宕机时表示是新验证码的宕机
    product: options.product, // 产品形式,包括:float,popup,bind
    width: options.width,
    lang: geetestLangMap[options.lang]
   }, function (captchaObj) {
        if(geetest.geetestObj){
         try {
          // 如果之前已经初始化过了,则线将之前生成的dom移除掉
          geetest.geetestObj.destroy();
         }catch (e) {
          console.error('极验销毁失败', e);
         }
        }
    geetest.geetestObj = captchaObj;
    if((options.product === 'popup' || options.product === 'custom' || options.product === 'float')){
     captchaObj.appendTo(options.area);
    }
    // 为bind模式时极验加载完成后自动弹出极验弹窗
    if(options.autoShow && options.product === 'bind'){
     captchaObj.onReady(() => {
      captchaObj.verify();
     });
    }
    geetest.geetestSuccessData = {};
    // 当用户操作后并且通过验证后的回调
    captchaObj.onSuccess(function () {
     let successData = captchaObj.getValidate();
     geetest.geetestSuccessData = successData;
     console.log('用户行为验证通过数据', successData);
     /*
      这种方式不可采用,原因,作用域会被缓存
      if (typeof options.callback === 'function') {
       options.callback(successData);
      }
      用户行为验证通过后调用回调函数
     */
     if(typeof that.onGeetestSuccess === 'function'){
      that.onGeetestSuccess(successData);
     }
    });
    captchaObj.onError(function (e) {
     console.error("极验出错了", e);
    });
    console.log('极验实例', captchaObj);
   });
  },
  // 调用接口,获取极验数据
  _geetestRegist_(options){
   if(this.geetest.geetestLoading){
    return;
   }
   this.geetest.geetestLoading = true;
   commonApi.getGtCaptcha()
    .then(res => {
     let data = res.data;
     // TIP 后台需要控制是否开启极验,因此需要判断 enable===true && success===1 才显示极限
     this.geetest.sign = data.sign;
     this.geetest.geetestFatched = true;
     if(typeof data.enable == "undefined" || (data.enable === true && data.success === 1)) {
      this.geetest.showGeetest = true;
     }else{
      this.geetest.showGeetest = false;
      this.geetest.geetestLoading = false;
      /*// 如果极验禁用,则调用onDisableGeetest回调
      if(typeof options.onDisableGeetest === 'function'){
       options.onDisableGeetest();
      }*/
      // 如果极验禁用,则调用onDisableGeetest回调
      if(typeof this.onDisableGeetest === 'function'){
       this.onDisableGeetest();
      }
      return
     }
     this.geetest.geetestLoading = false;
     this._initGeetestInternal_(data, options);
    })
    .catch((err) => {
     console.error('极验初始化失败', err);
     if(this.geetest.count > this.geetest.geetestRestartCountMax){
      this.geetest.geetestLoading = false;
      return;
     }
     console.log('正在重试初始化极验!当前次数:' + this.geetest.count);
     this.geetest.count++;
     this._geetestRegist_(options);
    });
  }
 },
 beforeDestroy(){
  if(this.geetest.geetestObj){
   this.geetest.geetestObj.destroy();
  }
 }
};

geetest.gt.js

段代码可以不用关注,极验官网有
/* initGeetest 1.0.0
 * 用于加载id对应的验证码库,并支持宕机模式
 * 暴露 initGeetest 进行验证码的初始化
 * 一般不需要用户进行修改
 */
var gtInit = (function (global, factory) {
 "use strict";
 if (typeof module === "object" && typeof module.exports === "object") {
  // CommonJS
  module.exports = global.document ?
   factory(global, true) :
   function (w) {
    if (!w.document) {
     throw new Error("Geetest requires a window with a document");
    }
    return factory(w);
   };
 } else {
  factory(global);
 }
})(typeof window !== "undefined" ? window : this, function (window, noGlobal) {
 "use strict";
 if (typeof window === 'undefined') {
  throw new Error('Geetest requires browser environment');
 }
 var document = window.document;
 var Math = window.Math;
 var head = document.getElementsByTagName("head")[0];

 function _Object(obj) {
  this._obj = obj;
 }

 _Object.prototype = {
  _each: function (process) {
   var _obj = this._obj;
   for (var k in _obj) {
    if (_obj.hasOwnProperty(k)) {
     process(k, _obj[k]);
    }
   }
   return this;
  }
 };
 function Config(config) {
  var self = this;
  new _Object(config)._each(function (key, value) {
   self[key] = value;
  });
 }

 Config.prototype = {
  api_server: 'api.geetest.com',
  protocol: 'http://',
  type_path: '/gettype.php',
  fallback_config: {
   slide: {
    static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"],
    type: 'slide',
    slide: '/static/js/geetest.0.0.0.js'
   },
   fullpage: {
    static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"],
    type: 'fullpage',
    fullpage: '/static/js/fullpage.0.0.0.js'
   }
  },
  _get_fallback_config: function () {
   var self = this;
   if (isString(self.type)) {
    return self.fallback_config[self.type];
   } else if (self.new_captcha) {
    return self.fallback_config.fullpage;
   } else {
    return self.fallback_config.slide;
   }
  },
  _extend: function (obj) {
   var self = this;
   new _Object(obj)._each(function (key, value) {
    self[key] = value;
   })
  }
 };
 var isNumber = function (value) {
  return (typeof value === 'number');
 };
 var isString = function (value) {
  return (typeof value === 'string');
 };
 var isBoolean = function (value) {
  return (typeof value === 'boolean');
 };
 var isObject = function (value) {
  return (typeof value === 'object' && value !== null);
 };
 var isFunction = function (value) {
  return (typeof value === 'function');
 };
 var callbacks = {};
 var status = {};
 var random = function () {
  return parseInt(Math.random() * 10000) + (new Date()).valueOf();
 };
 var loadScript = function (url, cb) {
  var script = document.createElement("script");
  script.charset = "UTF-8";
  script.async = true;
  script.onerror = function () {
   cb(true);
  };
  var loaded = false;
  script.onload = script.onreadystatechange = function () {
   if (!loaded &&
    (!script.readyState ||
     "loaded" === script.readyState ||
     "complete" === script.readyState)) {

    loaded = true;
    setTimeout(function () {
     cb(false);
    }, 0);
   }
  };
  script.src = url;
  head.appendChild(script);
 };
 var normalizeDomain = function (domain) {
  return domain.replace(/^https?:\/\/|\/$/g, '');
 };
 var normalizePath = function (path) {
  path = path.replace(/\/+/g, '/');
  if (path.indexOf('/') !== 0) {
   path = '/' + path;
  }
  return path;
 };
 var normalizeQuery = function (query) {
  if (!query) {
   return '';
  }
  var q = '?';
  new _Object(query)._each(function (key, value) {
   if (isString(value) || isNumber(value) || isBoolean(value)) {
    q = q + encodeURIComponent(key) + '=' + encodeURIComponent(value) + '&';
   }
  });
  if (q === '?') {
   q = '';
  }
  return q.replace(/&$/, '');
 };
 var makeURL = function (protocol, domain, path, query) {
  domain = normalizeDomain(domain);

  var url = normalizePath(path) + normalizeQuery(query);
  if (domain) {
   url = protocol + domain + url;
  }

  return url;
 };
 var load = function (protocol, domains, path, query, cb) {
  var tryRequest = function (at) {

   var url = makeURL(protocol, domains[at], path, query);
   loadScript(url, function (err) {
    if (err) {
     if (at >= domains.length - 1) {
      cb(true);
     } else {
      tryRequest(at + 1);
     }
    } else {
     cb(false);
    }
   });
  };
  tryRequest(0);
 };
 var jsonp = function (domains, path, config, callback) {
  if (isObject(config.getLib)) {
   config._extend(config.getLib);
   callback(config);
   return;
  }
  if (config.offline) {
   callback(config._get_fallback_config());
   return;
  }
  var cb = "geetest_" + random();
  window[cb] = function (data) {
   if (data.status === 'success') {
    callback(data.data);
   } else if (!data.status) {
    callback(data);
   } else {
    callback(config._get_fallback_config());
   }
   window[cb] = undefined;
   try {
    delete window[cb];
   } catch (e) {
   }
  };
  load(config.protocol, domains, path, {
   gt: config.gt,
   callback: cb
  }, function (err) {
   if (err) {
    callback(config._get_fallback_config());
   }
  });
 };
 var throwError = function (errorType, config) {
  var errors = {
   networkError: '网络错误'
  };
  if (typeof config.onError === 'function') {
   config.onError(errors[errorType]);
  } else {
   throw new Error(errors[errorType]);
  }
 };
 var detect = function () {
  return !!window.Geetest;
 };
 if (detect()) {
  status.slide = "loaded";
 }
 var initGeetest = function (userConfig, callback) {
  var config = new Config(userConfig);
  if (userConfig.https) {
   config.protocol = 'https://';
  } else if (!userConfig.protocol) {
   config.protocol = window.location.protocol + '//';
  }
  jsonp([config.api_server || config.apiserver], config.type_path, config, function (newConfig) {
   var type = newConfig.type;
   var init = function () {
    config._extend(newConfig);
    callback(new window.Geetest(config));
   };
   callbacks[type] = callbacks[type] || [];
   var s = status[type] || 'init';
   if (s === 'init') {
    status[type] = 'loading';
    callbacks[type].push(init);
    load(config.protocol, newConfig.static_servers || newConfig.domains, newConfig[type] || newConfig.path, null, function (err) {
     if (err) {
      status[type] = 'fail';
      throwError('networkError', config);
     } else {
      status[type] = 'loaded';
      var cbs = callbacks[type];
      for (var i = 0, len = cbs.length; i < len; i = i + 1) {
       var cb = cbs[i];
       if (isFunction(cb)) {
        cb();
       }
      }
      callbacks[type] = [];
     }
    });
   } else if (s === "loaded") {
    init();
   } else if (s === "fail") {
    throwError('networkError', config);
   } else if (s === "loading") {
    callbacks[type].push(init);
   }
  });
 };
 window.initGeetest = initGeetest;
 return initGeetest;
});

export default {
 gtInit
}

页面中使用

// 导入极验验证
import {geetestMixin} from "./geetest-mixin";
import {mapGetters} from "vuex";
import {commonApi} from "../api/commonApi";

export default {
 name: 'Regist',
 mixins: [geetestMixin],
 data(){
  return {
   form: {
    ...表单数据
   },
   committing: false,
   errMsg: ' ',.
  }
 },
 methods: {
  // 提交注册数据
  submitRegistData(){
   ...你的业务逻辑
   /*if(this.geetest.showGeetest){
    // 如果没有geetest_challenge,则说明用户没有进行行为验证
    if(!this.geetest.geetestSuccessData.geetest_challenge){
     this.errMsg = this.$t('formError.geetest'); // 点击按钮进行验证
     return;
    }
   }*/
   this.errMsg = '';


   if(!this.geetest.geetestObj){
    /*
     如果this.geetest.geetestFatched==true,则说明已经加载过极验了
     如果this.geetest.showGeetest==false,则说明后台关闭极验了
     */
    if(this.geetest.geetestFatched && !this.geetest.showGeetest){
     //this.committing = true;
     this.commitData();
    }else{
     this.initGeetest({
      product: 'bind',
      lang: this.get_lang.code,
     });
    }
   }else{
    if(this.geetest.showGeetest){
     this.geetestShow();
    }else{
     console.log('fasfsafsdfsd')
     //this.committing = true;
     this.commitData();
    }
   }
  },
  // 提交数据
  commitData(){
   if(this.committing){
    return;
   }
   this.committing = true;
   let data = {
    ...this.form
   };
   let geetestData = {};
   // 获取极验数据
   if(this.geetest.showGeetest){
    geetestData = {
     ...this.geetest.geetestSuccessData,
     sign: this.geetest.sign
    }
   }
   if(!this.form.inviteCode){
    delete data.inviteCode;
   }
   commonApi.regist(data, geetestData)
    .then(res => {
     this.committing = false;
     if(res.errcode === 0){
      ...你的业务逻辑
     }else{
     // 重置极验,使极验回到可操作状态
      this.geetestReset();
     }
    })
    .catch(() => {
     this.committing = false;
     // 重置极验,使极验回到可操作状态
     this.geetestReset();
    });
  },
  // 极验验证成功后回调
  onGeetestSuccess(){
   // 用户通过极验行为验证后做的操作
   this.commitData();
  },
  // 极验被禁用后回调
  onDisableGeetest(){
   this.commitData();
  }
 },
 computed: {
  ...mapGetters(['get_lang'])
 }
};

3、极验初始化时间问题

geetest-mixin.js设计的比较灵活,它可以允许你在任何时机初始化极验。但在项目中推荐在需要使用到的时候再初始化,1来可以节省流量;2来可以提升页面性能;3是最重要的一个点,在单页面应用程序中都是通过接口来访问数据的,而接口都有过期时间,如果组件初始化完成就立即初始化极验,而用户在接口过期后再作则会出现一些奇葩的bug

4、多语言项目中用户手动切换语言的问题

由于单页面应用程序切换语言后页面不会刷新,所以就会出现页面语言已经切换了,但极验还是使用的原来的语言。我的解决方案就是在用户切换语言后手动的刷新一下极验

{
 watch: {
  get_lang(lang){
   let options = this.geetest.geetestOptions;
   // 如果开启了语言切换自手动刷新极验,并且极验已经初始化了则刷新。如果极验都还没有初始化则可以不用去刷新
   if(options.autoRefreshOnLangChange && this.geetest.geetestObj){
    this.initGeetest({
     ...options,
     lang: lang.code
    });
   }
  }
 }
}

5、关于点击按钮时按钮loading效果的控制

如《效果预览》图中的获取验证码loading效果控制,可以通过geetest.geetestLoading来进行判断

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持爱安网。

最新资讯
马斯克称不在乎求职者学历 但招聘信息出卖了他

马斯克称不在乎求职者

特斯拉CEO埃隆·马斯克(Elon Musk)本月初曾表示,他不在乎
阿里发爱心助农五条准则:以净重为准 品质差将拦截

阿里发爱心助农五条准

阿里巴巴集团向平台商家发布公告,强调平台会持续从商家
小米高管任命:王川任CSO 李肖爽任大家电部总经理

小米高管任命:王川任CS

小米集团刚刚宣布新的架构调整,任命小米集团联合创始人
北京网约车开装“安全舱”,3月2日前8000辆车配齐

北京网约车开装“安全

记者获悉,北京所有的滴滴网约车正陆续装上一层前后排塑
特斯拉德国超级工厂第一阶段将雇佣12000人

特斯拉德国超级工厂第

特斯拉在官网披露的信息显示,德国超级工厂的第一阶段,计
小鹏汽车发生工商变更 中金资本等退出其股东行列

小鹏汽车发生工商变更

广州橙行智动汽车科技有限公司发生工商变更,河南省战新
最新文章
Vue实现图片与文字混输效果

Vue实现图片与文字混

用多了 JQuery ,习惯了使用JQuery的API操作 DOM ,几乎忘
Vue实现点击当前元素以外的地方隐藏当前元素(实现思路)

Vue实现点击当前元素

这篇文章主要介绍了Vue实现点击当前元素以外的地方隐
Vue实现验证码功能

Vue实现验证码功能

这篇文章主要为大家详细介绍了Vue实现验证码功能,文中
JS实现的雪花飘落特效示例

JS实现的雪花飘落特效

这篇文章主要介绍了JS实现的雪花飘落特效,结合实例形
微信小程序实现图片压缩

微信小程序实现图片压

这篇文章主要为大家详细介绍了微信小程序实现图片压缩
JavaScript实现京东放大镜效果

JavaScript实现京东放

这篇文章主要为大家详细介绍了JavaScript实现京东放大