这篇文章主要介绍了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来进行判断

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

最新资讯
特斯拉:将自主研发新电池 预计4月正式宣布

特斯拉:将自主研发新电

特斯拉相关人士表示,特斯拉将自主研发新电池,预计会在4
苹果春季发布会或3月底举办:预计发布多款硬件新品

苹果春季发布会或3月

来自iPhone-ticker.de网站的消息称,苹果计划在今年3月3
微博将于2月26日发布2019年第四季度及全年财报

微博将于2月26日发布2

微博公司 定于美国东部时间2020年2月26日美国股市开盘
捐赠100万元后 得物App将1万件隔离衣等物资送往湖北

捐赠100万元后 得物Ap

得物App(原毒App)捐赠的第二批医疗物资近日发往武汉,包括
苹果美股盘前跌超4% 3月季度营收目标将无法实现

苹果美股盘前跌超4% 3

苹果美股盘前跌超4%。此前苹果对外宣布,受疫情影响,全球
棋(ma)牌(jiang)、换装类游戏春节增长最快,字节跳动成搅局者

棋(ma)牌(jiang)、换装类游戏春节

2020年春节期间下载量TOP10游戏中有3款来自字节跳动。
最新文章
Vue实现图片与文字混输效果

Vue实现图片与文字混

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

Vue实现点击当前元素

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

Vue实现验证码功能

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

JS实现的雪花飘落特效

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

微信小程序实现图片压

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

JavaScript实现京东放

这篇文章主要为大家详细介绍了JavaScript实现京东放大
炸金花 传奇私服 江西快3 炸金花