溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

vue項(xiàng)目中極驗(yàn)驗(yàn)證的使用代碼示例

發(fā)布時(shí)間:2020-10-12 20:27:33 來(lái)源:腳本之家 閱讀:176 作者:heath_learning 欄目:web開發(fā)
使用vue、react的項(xiàng)目獲取數(shù)據(jù)、上傳數(shù)據(jù)、注冊(cè)、登陸等都是通過(guò)接口來(lái)完成的,接口很容易被人惡意調(diào)用,最容易被人惡意調(diào)用的接口就是注冊(cè)、登陸類的接口,為了防止接口被惡意調(diào)用很多公司開發(fā)了出了很多的人機(jī)驗(yàn)證的工具,今天就來(lái)講下極驗(yàn)驗(yàn)證在vue項(xiàng)目中的使用。

效果預(yù)覽

vue項(xiàng)目中極驗(yàn)驗(yàn)證的使用代碼示例

1、遇到的問(wèn)題

  • 在項(xiàng)目中任何一個(gè)頁(yè)面或vue組件都有可能需要使用到極驗(yàn),并且極驗(yàn)在初始化時(shí)需要傳遞一些參數(shù),要怎么做才能做到每一個(gè)組件都能很方便的使用極驗(yàn)?zāi)兀?/li>
  • 極驗(yàn)應(yīng)該在什么時(shí)候初始化?是組件一加載就初始化還是用戶點(diǎn)擊按鈕后再初始化?
  • 在多語(yǔ)言項(xiàng)目中,用戶手動(dòng)切換語(yǔ)言后的極驗(yàn)重置

2、代碼分享

為了在多個(gè)頁(yè)面或多個(gè)組件中都能方便的使用極驗(yàn),我將極驗(yàn)初始化的相關(guān)代碼寫到了mixins中。這樣做的好處是:方便在組件中獲取極驗(yàn)相關(guān)的數(shù)據(jù),以及調(diào)用極驗(yàn)相關(guān)api,如做重置、銷毀等操作;缺點(diǎn)是:在同一個(gè)頁(yè)面中無(wú)法在多個(gè)地方使用mixin,但這也是有解決方案的。

geetest-mixin.js

/*
 極驗(yàn)mixin
 */
// 導(dǎo)入極驗(yàn)官方給的代碼
import gt from "../common/js/geetest/geetest.gt";
import {commonApi} from "../api/commonApi";
import {mapGetters} from "vuex";
// 自定義語(yǔ)言與極驗(yàn)語(yǔ)言對(duì)應(yīng)表
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)
// 極驗(yàn)?zāi)J(rèn)配置
const geetestOptions = {
 product: 'popup', // 極驗(yàn)展現(xiàn)形式 可選值有 float、popup、custom、bind
 width: '100%',
 lang: 'zh_CN',
 autoShow: true, // 當(dāng)product為bind時(shí),如果次參數(shù)為true,則在極驗(yàn)加載完成后立即顯示極驗(yàn)彈窗
 area: null, // 極驗(yàn)綁定的元素,僅在 product為 custom、float、popup時(shí)需要傳遞
 autoRefreshOnLangChange: true, // 語(yǔ)言改變時(shí)是否自動(dòng)刷新
};
export const geetestMixin = {
 data(){
  return {
   geetest: {
    geetestSuccessData: null, // 極驗(yàn)用戶行為操作成功后的數(shù)據(jù)
    geetestObj: null, // 極驗(yàn)對(duì)象
    geetestLoading: false,
    geetestFatched: false, // 判斷是否從服務(wù)器獲取了極驗(yàn)數(shù)據(jù)
    showGeetest: false, // 是否使用極驗(yàn)
    sign: "", // 極驗(yàn)降級(jí) 用的簽名
    geetestRestartCountMax: 5, // 極驗(yàn)重試最大此時(shí)
    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: {
  // 初始化極驗(yàn)
  initGeetest(options){
   if(!options || ({}).toString.call(options) !== '[object Object]'){
    console.error('initGeetest方法的參數(shù)options必須是一個(gè)對(duì)象!');
    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時(shí)options參數(shù)中必須有area屬性,area屬性值可以為css選擇器或dom元素!');
    return;
   }
   this.geetest.geetestOptions = newOptions;
   this._geetestRegist_(newOptions);
  },
  // 重置極驗(yàn)
  geetestReset(cb){
   if(this.geetest.geetestObj){
    this.geetest.geetestSuccessData = {};
    this.geetest.geetestObj.reset();
    if(typeof cb === 'function'){
     cb();
    }
   }else{
    console.error('極驗(yàn)不存在!');
   }
  },
  // 顯示極驗(yàn)彈窗,此方法只有在product為bind時(shí)才有效
  geetestShow(){
   if(this.geetest.geetestObj){
    if(this.geetest.geetestOptions.product === 'bind'){
     this.geetest.geetestObj.verify();
    }else{
     console.error('極驗(yàn)的product值非bind,無(wú)法調(diào)用show!');
    }
   }else{
    console.error('極驗(yàn)不存在!');
   }
  },
  // 初始化極驗(yàn),內(nèi)部使用
  _initGeetestInternal_(data, options){
   let that = this;
   let geetest = this.geetest;

   window.initGeetest({
    // 以下 4 個(gè)配置參數(shù)為必須,不能缺少
    gt: data.gt,
    challenge: data.challenge,
    offline: !data.success, // 表示用戶后臺(tái)檢測(cè)極驗(yàn)服務(wù)器是否宕機(jī)
    new_captcha: true, // 用于宕機(jī)時(shí)表示是新驗(yàn)證碼的宕機(jī)
    product: options.product, // 產(chǎn)品形式,包括:float,popup,bind
    width: options.width,
    lang: geetestLangMap[options.lang]
   }, function (captchaObj) {
        if(geetest.geetestObj){
         try {
          // 如果之前已經(jīng)初始化過(guò)了,則線將之前生成的dom移除掉
          geetest.geetestObj.destroy();
         }catch (e) {
          console.error('極驗(yàn)銷毀失敗', e);
         }
        }
    geetest.geetestObj = captchaObj;
    if((options.product === 'popup' || options.product === 'custom' || options.product === 'float')){
     captchaObj.appendTo(options.area);
    }
    // 為bind模式時(shí)極驗(yàn)加載完成后自動(dòng)彈出極驗(yàn)彈窗
    if(options.autoShow && options.product === 'bind'){
     captchaObj.onReady(() => {
      captchaObj.verify();
     });
    }
    geetest.geetestSuccessData = {};
    // 當(dāng)用戶操作后并且通過(guò)驗(yàn)證后的回調(diào)
    captchaObj.onSuccess(function () {
     let successData = captchaObj.getValidate();
     geetest.geetestSuccessData = successData;
     console.log('用戶行為驗(yàn)證通過(guò)數(shù)據(jù)', successData);
     /*
      這種方式不可采用,原因,作用域會(huì)被緩存
      if (typeof options.callback === 'function') {
       options.callback(successData);
      }
      用戶行為驗(yàn)證通過(guò)后調(diào)用回調(diào)函數(shù)
     */
     if(typeof that.onGeetestSuccess === 'function'){
      that.onGeetestSuccess(successData);
     }
    });
    captchaObj.onError(function (e) {
     console.error("極驗(yàn)出錯(cuò)了", e);
    });
    console.log('極驗(yàn)實(shí)例', captchaObj);
   });
  },
  // 調(diào)用接口,獲取極驗(yàn)數(shù)據(jù)
  _geetestRegist_(options){
   if(this.geetest.geetestLoading){
    return;
   }
   this.geetest.geetestLoading = true;
   commonApi.getGtCaptcha()
    .then(res => {
     let data = res.data;
     // TIP 后臺(tái)需要控制是否開啟極驗(yàn),因此需要判斷 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;
      /*// 如果極驗(yàn)禁用,則調(diào)用onDisableGeetest回調(diào)
      if(typeof options.onDisableGeetest === 'function'){
       options.onDisableGeetest();
      }*/
      // 如果極驗(yàn)禁用,則調(diào)用onDisableGeetest回調(diào)
      if(typeof this.onDisableGeetest === 'function'){
       this.onDisableGeetest();
      }
      return
     }
     this.geetest.geetestLoading = false;
     this._initGeetestInternal_(data, options);
    })
    .catch((err) => {
     console.error('極驗(yàn)初始化失敗', err);
     if(this.geetest.count > this.geetest.geetestRestartCountMax){
      this.geetest.geetestLoading = false;
      return;
     }
     console.log('正在重試初始化極驗(yàn)!當(dāng)前次數(shù):' + this.geetest.count);
     this.geetest.count++;
     this._geetestRegist_(options);
    });
  }
 },
 beforeDestroy(){
  if(this.geetest.geetestObj){
   this.geetest.geetestObj.destroy();
  }
 }
};

geetest.gt.js

段代碼可以不用關(guān)注,極驗(yàn)官網(wǎng)有
/* initGeetest 1.0.0
 * 用于加載id對(duì)應(yīng)的驗(yàn)證碼庫(kù),并支持宕機(jī)模式
 * 暴露 initGeetest 進(jìn)行驗(yàn)證碼的初始化
 * 一般不需要用戶進(jìn)行修改
 */
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: '網(wǎng)絡(luò)錯(cuò)誤'
  };
  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
}

頁(yè)面中使用

// 導(dǎo)入極驗(yàn)驗(yàn)證
import {geetestMixin} from "./geetest-mixin";
import {mapGetters} from "vuex";
import {commonApi} from "../api/commonApi";

export default {
 name: 'Regist',
 mixins: [geetestMixin],
 data(){
  return {
   form: {
    ...表單數(shù)據(jù)
   },
   committing: false,
   errMsg: ' ',.
  }
 },
 methods: {
  // 提交注冊(cè)數(shù)據(jù)
  submitRegistData(){
   ...你的業(yè)務(wù)邏輯
   /*if(this.geetest.showGeetest){
    // 如果沒有g(shù)eetest_challenge,則說(shuō)明用戶沒有進(jìn)行行為驗(yàn)證
    if(!this.geetest.geetestSuccessData.geetest_challenge){
     this.errMsg = this.$t('formError.geetest'); // 點(diǎn)擊按鈕進(jìn)行驗(yàn)證
     return;
    }
   }*/
   this.errMsg = '';


   if(!this.geetest.geetestObj){
    /*
     如果this.geetest.geetestFatched==true,則說(shuō)明已經(jīng)加載過(guò)極驗(yàn)了
     如果this.geetest.showGeetest==false,則說(shuō)明后臺(tái)關(guān)閉極驗(yàn)了
     */
    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();
    }
   }
  },
  // 提交數(shù)據(jù)
  commitData(){
   if(this.committing){
    return;
   }
   this.committing = true;
   let data = {
    ...this.form
   };
   let geetestData = {};
   // 獲取極驗(yàn)數(shù)據(jù)
   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){
      ...你的業(yè)務(wù)邏輯
     }else{
     // 重置極驗(yàn),使極驗(yàn)回到可操作狀態(tài)
      this.geetestReset();
     }
    })
    .catch(() => {
     this.committing = false;
     // 重置極驗(yàn),使極驗(yàn)回到可操作狀態(tài)
     this.geetestReset();
    });
  },
  // 極驗(yàn)驗(yàn)證成功后回調(diào)
  onGeetestSuccess(){
   // 用戶通過(guò)極驗(yàn)行為驗(yàn)證后做的操作
   this.commitData();
  },
  // 極驗(yàn)被禁用后回調(diào)
  onDisableGeetest(){
   this.commitData();
  }
 },
 computed: {
  ...mapGetters(['get_lang'])
 }
};

3、極驗(yàn)初始化時(shí)間問(wèn)題

geetest-mixin.js設(shè)計(jì)的比較靈活,它可以允許你在任何時(shí)機(jī)初始化極驗(yàn)。但在項(xiàng)目中推薦在需要使用到的時(shí)候再初始化,1來(lái)可以節(jié)省流量;2來(lái)可以提升頁(yè)面性能;3是最重要的一個(gè)點(diǎn),在單頁(yè)面應(yīng)用程序中都是通過(guò)接口來(lái)訪問(wèn)數(shù)據(jù)的,而接口都有過(guò)期時(shí)間,如果組件初始化完成就立即初始化極驗(yàn),而用戶在接口過(guò)期后再去操作則會(huì)出現(xiàn)一些奇葩的bug

4、多語(yǔ)言項(xiàng)目中用戶手動(dòng)切換語(yǔ)言的問(wèn)題

由于單頁(yè)面應(yīng)用程序切換語(yǔ)言后頁(yè)面不會(huì)刷新,所以就會(huì)出現(xiàn)頁(yè)面語(yǔ)言已經(jīng)切換了,但極驗(yàn)還是使用的原來(lái)的語(yǔ)言。我的解決方案就是在用戶切換語(yǔ)言后手動(dòng)的刷新一下極驗(yàn)

{
 watch: {
  get_lang(lang){
   let options = this.geetest.geetestOptions;
   // 如果開啟了語(yǔ)言切換自手動(dòng)刷新極驗(yàn),并且極驗(yàn)已經(jīng)初始化了則刷新。如果極驗(yàn)都還沒有初始化則可以不用去刷新
   if(options.autoRefreshOnLangChange && this.geetest.geetestObj){
    this.initGeetest({
     ...options,
     lang: lang.code
    });
   }
  }
 }
}

5、關(guān)于點(diǎn)擊按鈕時(shí)按鈕loading效果的控制

如《效果預(yù)覽》圖中的獲取驗(yàn)證碼loading效果控制,可以通過(guò)geetest.geetestLoading來(lái)進(jìn)行判斷

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI