flutter 人机验证实战

先看效果

基本思路

接口进行触发是否进行图像验证,验证后将结果携带到接口里面去,进行人机验证

使用的技术(可惜只有web版本的)

验证码2.0智能人机验证(VAPTCHA)- 安全、易用、完全免费手势验证码VAPTCHA是基于人工智能和大数据的次世代人机验证解决方案。独有的验证策略及风控模型组合可彻底杜绝刷票、灌水、撞库等恶意攻击行为。icon-default.png?t=N7T8https://www.vaptcha.com/

本来想使用flutter 实现一个插件 来调用安卓的ios,写的过程发现 vaptcha 的原生使用的是webview实现的,额 还是使用web版本进行封装把

代码如下

webview代码

import 'dart:convert';
import 'dart:io';import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';class AppWebView extends StatefulWidget {final String url;final Function(dynamic)? onMessageReceived;const AppWebView({super.key,required this.url,this.onMessageReceived,});@overrideState<AppWebView> createState() => _AppWebViewState();
}class _AppWebViewState extends State<AppWebView> {late final WebViewController controller;int progress = 0;@overridevoid initState() {super.initState();controller = WebViewController()..setJavaScriptMode(JavaScriptMode.unrestricted)..addJavaScriptChannel("lh", onMessageReceived: onMessageReceived)..enableZoom(true)..setBackgroundColor(const Color(0x00000000))..setNavigationDelegate(NavigationDelegate(onProgress: (int progress) {// Update loading bar.this.progress = progress;setState(() {});},onPageStarted: (String url) {},onPageFinished: (String url) {},onWebResourceError: (WebResourceError error) {},onNavigationRequest: (NavigationRequest request) {if (request.url.startsWith('https://www.youtube.com/')) {return NavigationDecision.prevent;}return NavigationDecision.navigate;},),)..loadRequest(Uri.parse(widget.url));}// 接受h5发送来的数据onMessageReceived(message) async {widget.onMessageReceived?.call(message);//接收H5发过来的数据String sendMesStr = message.message;print("onMessageReceived sendMesStr:${sendMesStr}");Map<String, dynamic> msg = json.decode(sendMesStr);String method = msg["method"] ?? "";// Map<String, dynamic> data = msg["data"] ?? {};if (method.isNotEmpty) {switch (method) {case "back":controller.goBack();break;}}}@overrideWidget build(BuildContext context) {if (!kIsWeb && (Platform.isIOS || Platform.isAndroid)) {return Scaffold(// appBar: AppBar(title: const Text('Flutter Simple Example')),body: Stack(children: [WebViewWidget(controller: controller),if (progress != 100)const Center(child: CupertinoActivityIndicator(),)]),);} else {return const Center(child: Text('WebView control is not supported on this platform yet.'),);}}
}

封装的核心

import 'dart:convert';import 'package:LS/common/api/api.dart';
import 'package:LS/common/utils/toast.dart';
import 'package:LS/common/widgets/app_webview.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';class Captcha {static show() {AppToast.dialog(title: "图像验证".tr,showBtn: false,SizedBox(height: 350.h,child: const AppWebView(url: "https://genaertest.wbnr.xyz/captcha",onMessageReceived: onMessageReceived,),),);}static onMessageReceived(message) async {//接收H5发过来的数据String sendMesStr = message.message;print("onMessageReceived sendMesStr:${sendMesStr}");Map<String, dynamic> msg = json.decode(sendMesStr);String method = msg["method"] ?? "";Map<String, dynamic> data = msg["data"] ?? {};String server = data["server"] ?? "";String token = data["token"] ?? "";if (method.isNotEmpty) {switch (method) {case "getServerToken":try {// 调用后端接口final res = await Api.captchaVerify(server: server, token: token);final data = res["data"] ?? {};if (data["success"] == 1) {AppToast.show("验证通过");}// 关闭 SmartDialog  弹窗SmartDialog.dismiss();} catch (e) {SmartDialog.dismiss();}break;}}}
}

弹窗使用的是flutter_smart_dialog 可以自己集成一下

flutter_smart_dialog | Flutter PackageAn elegant Flutter Dialog solution, Easily implement Toast, Loading and custom Dialog, Make the use of the dialog easier!icon-default.png?t=N7T8https://pub-web.flutter-io.cn/packages/flutter_smart_dialog

 AppToast.dialog 其实是下面的封装

 SmartDialog.show(

      builder: (_) {

        return child;

      },

      keepSingle: true,

      clickMaskDismiss: clickMaskDismiss,

      usePenetrate: false,

      maskWidget: maskWidget,

    );

然后是网页代码

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta http-equiv="X-UA-Compatible" content="ie=edge" /><title></title><style>/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */html {line-height: 1.15;-webkit-text-size-adjust: 100%;}body {margin: 0;}main {display: block;}h1 {font-size: 2em;margin: 0.67em 0;}hr {box-sizing: content-box;height: 0;overflow: visible;}pre {font-family: monospace, monospace;font-size: 1em;}a {background-color: transparent;}abbr[title] {border-bottom: none;text-decoration: underline;text-decoration: underline dotted;}b,strong {font-weight: bolder;}code,kbd,samp {font-family: monospace, monospace;font-size: 1em;}small {font-size: 80%;}sub,sup {font-size: 75%;line-height: 0;position: relative;vertical-align: baseline;}sub {bottom: -0.25em;}sup {top: -0.5em;}img {border-style: none;}button,input,optgroup,select,textarea {font-family: inherit;font-size: 100%;line-height: 1.15;margin: 0;}button,input {overflow: visible;}button,select {text-transform: none;}[type="button"],[type="reset"],[type="submit"],button {-webkit-appearance: button;}[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner,button::-moz-focus-inner {border-style: none;padding: 0;}[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring,button:-moz-focusring {outline: 1px dotted ButtonText;}fieldset {padding: 0.35em 0.75em 0.625em;}legend {box-sizing: border-box;color: inherit;display: table;max-width: 100%;padding: 0;white-space: normal;}progress {vertical-align: baseline;}textarea {overflow: auto;}[type="checkbox"],[type="radio"] {box-sizing: border-box;padding: 0;}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button {height: auto;}[type="search"] {-webkit-appearance: textfield;outline-offset: -2px;}[type="search"]::-webkit-search-decoration {-webkit-appearance: none;}::-webkit-file-upload-button {-webkit-appearance: button;font: inherit;}details {display: block;}summary {display: list-item;}template {display: none;}[hidden] {display: none;}/*# sourceMappingURL=normalize.min.css.map */</style><style>.VAPTCHA-init-main {display: table;width: 100%;height: 100%;background-color: #eeeeee;position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);}.VAPTCHA-init-loading {display: table-cell;vertical-align: middle;text-align: center;}.VAPTCHA-init-loading > a {display: inline-block;width: 18px;height: 18px;border: none;}.VAPTCHA-init-loading .VAPTCHA-text {font-family: sans-serif;font-size: 12px;color: #cccccc;vertical-align: middle;}#VAPTCHAContainer {width: 240px;height: 36px;position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);}</style><!-- <script src="https://v-cn.vaptcha.com/v3.js"></script> --><script>!(function () {"use strict";function e(e) {return e === undefined || null === e;}function t(e) {return e !== undefined && null !== e;}function n(e) {return null !== e && "object" === (void 0 === e ? "undefined" : p(e));}function a(e) {return ("object" === (void 0 === e ? "undefined" : p(e)) &&e instanceof HTMLElement);}function r(e) {var t = e && e.toString().match(/^\s*function (\w+)/);return t ? t[1] : "";}function o(e) {var t =arguments.length > 1 && arguments[1] !== undefined? arguments[1]: {};for (var n in t) e[n] = t[n];return e;}function i(e) {var t = Object.create(null);return function (n) {return t[n] || (t[n] = e(n));};}function c(e) {return h.call(e).slice(8, -1);}function u(e) {throw new Error(e);}function l() {if (navigator.cookieEnabled) {localStorage.setItem("vaptchatemp1", "1");var e = localStorage.getItem("vaptchatemp1");return localStorage.removeItem("vaptchatemp1"), !!e;}return !1;}function Promise(e) {var t = this;(this.state = "pending"),(this.value = undefined),(this.reason = undefined),(this.onResolveAsyncCallbacks = []),(this.onRejectAsyncCallbacks = []);var n = function (e) {"pending" === t.state &&((t.state = "fulfilled"),(t.value = e),t.onResolveAsyncCallbacks.map(function (e) {return e();}));},a = function (e) {"pending" === t.state &&((t.state = "rejected"),(t.reason = e),t.onRejectAsyncCallbacks.map(function (t) {return t(e);}));};try {e(n, a);} catch (r) {a(r);}}function s(e, t) {if (!(e instanceof t))throw new TypeError("Cannot call a class as a function");}function f() {var e = navigator.language || navigator.userLanguage;return "zh-CN" === e? "zh-CN": "zh-TW" === e? "zh-TW": e.includes("en", -1)? "en": e.includes("ja", -1)? "jp": e.includes("vi", -1)? "vi": "zh-CN";}(window.HTMLElement = window.HTMLElement || Element),Array.prototype.map ||(Array.prototype.map = function (e, t) {var n, a, r;if (null == this)throw new TypeError(" this is null or not defined");var o = Object(this),i = o.length >>> 0;if ("[object Function]" != Object.prototype.toString.call(e))throw new TypeError(e + " is not a function");for (t && (n = t), a = new Array(i), r = 0; r < i; ) {var c, u;r in o && ((c = o[r]), (u = e.call(n, c, r, o)), (a[r] = u)),r++;}return a;}),Array.prototype.includes ||(Array.prototype.includes = function (e, t) {if (null == this)throw new TypeError('"this" is null or not defined');var n = Object(this),a = n.length >>> 0;if (0 === a) return !1;for (var r = 0 | t, o = Math.max(r >= 0 ? r : a - Math.abs(r), 0);o < a;) {if (n[o] === e) return !0;o++;}return !1;}),Array.prototype.findIndex ||(Array.prototype.findIndex = function (e) {if (null == this)throw new TypeError('"this" is null or not defined');var t = Object(this),n = t.length >>> 0;if ("function" != typeof e)throw new TypeError("predicate must be a function");for (var a = arguments[1], r = 0; r < n; ) {if (e.call(a, t[r], r, t)) return r;r++;}return -1;}),Object.create ||(Object.create = function (e) {var t = function () {};return (t.prototype = e), new t();});var d = {vid: null,scene: 0,container: null,mode: "popup",style: "dark",lang: "auto",ai: !0,https: !0,guide: !0,aiAnimation: !1,protocol: "https://",css_version: "2.9.12",cdn_servers: ["statics.vaptcha.com"],api_server: "api.vaptcha.com/v3",canvas_path: "/canvas.min.js",offline_server: "",},p ="function" == typeof Symbol && "symbol" == typeof Symbol.iterator? function (e) {return typeof e;}: function (e) {return e &&"function" == typeof Symbol &&e.constructor === Symbol &&e !== Symbol.prototype? "symbol": typeof e;},h = Object.prototype.toString,v =(i(function (e) {for (var t = {},n =(e && -1 !== e.indexOf("?") && e.split("?")[1]) ||window.location.search.substring(1),a = n.split("&"),r = 0;r < a.length;r++) {var o = a[r].split("=");t[decodeURIComponent(o[0])] = decodeURIComponent(o[1]);}return t;}),i(function (e) {return e.charAt(0).toUpperCase() + e.slice(1);})),g = function (t) {(this.data = t),(this.valiudateFuns = []),(this.ruleFuns = {required: function (t, n) {return e(t) || 0 === t.length ? n : null;},});};g.prototype = {constructor: g,addValidateRules: function (e) {o(this.ruleFuns, e);},add: function (e, t, n) {var a = this,r = t.split(":"),o = r.shift(),i = this.ruleFuns[o];r.unshift(this.data[e]),r.push(n),i? this.valiudateFuns.push(function () {return i.apply(a, r);}): console.warn("Validator warning: rule " + o + " is not defined");},validate: function () {for (var e, t = 0; (e = this.valiudateFuns[t++]); ) {var n = e();if (n) return u(n), !1;}return !0;},};var m = {AccessDenied: "0101",RefreshAgain: "0102",Success: "0103",Fail: "0104",RefreshTooFast: "0105",RefreshTanto: "0106",DrawTanto: "0107",Attack: "0108",jsonpTimeOut: "0703",challengeExpire: "1002",};(Promise.prototype.then = function (e) {var t = this;if ("fulfilled" === this.state) {var a = e(this.value);if (n(a) && "Promise" === r(a.constructor)) return a;}return "pending" === this.state? new Promise(function (a) {t.onResolveAsyncCallbacks.push(function () {var o = e(t.value);if (n(o) && "Promise" === r(o.constructor)) return o.then(a);a(o);});}): this;}),(Promise.prototype["catch"] = function (e) {return ("rejected" === this.state && e(this.reason),"pending" === this.state && this.onRejectAsyncCallbacks.push(e),this);}),(Promise.resolve = function (e) {return new Promise(function (t) {t(e);});}),(Promise.reject = function (e) {return new Promise(function (t, n) {n(e);});});var y = (function () {function e(e, t) {for (var n = 0; n < t.length; n++) {var a = t[n];(a.enumerable = a.enumerable || !1),(a.configurable = !0),"value" in a && (a.writable = !0),Object.defineProperty(e, a.key, a);}}return function (t, n, a) {return n && e(t.prototype, n), a && e(t, a), t;};})(),w = (function () {function e() {s(this, e);}return (y(e, [{key: "GenerateFP",value: function () {return this.extractCRC32FromBase64(this.getComplexCanvasFingerprint(arguments.length > 0 && arguments[0] !== undefined? arguments[0]: ""));},},{key: "getComplexCanvasFingerprint",value: function () {var e =arguments.length > 0 && arguments[0] !== undefined? arguments[0]: "",t = "BrowserLeaks,com <canvas> 1.0" + e,n = document.createElement("canvas");n.setAttribute("width", "220"),n.setAttribute("height", "30");var a = n.getContext("2d");return ((a.textBaseline = "top"),(a.font = "14px 'Arial'"),(a.textBaseline = "alphabetic"),(a.fillStyle = "#f60"),a.fillRect(125, 1, 62, 20),(a.fillStyle = "#069"),a.fillText(t, 2, 15),(a.fillStyle = "rgba(102, 204, 0, 0.7)"),a.fillText(t, 4, 17),n.toDataURL());},},{key: "extractCRC32FromBase64",value: function (e) {return ((e = e.replace("data:image/png;base64,", "")),this.string2Hex(atob(e).slice(-16, -12).toString()));},},{key: "string2Hex",value: function (e) {for (var t = "", n = 0; n < e.length; n++) {var a = e.charCodeAt(n);a <= 15 && (t += "0"),(t += a.toString(16).toLocaleUpperCase());}return t;},},]),e);})(),T =(new w(),(function () {var e = d.protocol,t = d.api_server,n = function (e) {var t = "";for (var n in e)Object.prototype.hasOwnProperty.call(e, n) &&(t += "&" + n + "=" + encodeURIComponent(e[n]));return t;},a = function (a, r) {var o = n(r),i = a.indexOf("http://") > -1 || a.indexOf("https://") > -1;return (a.indexOf("?") < 0 && (o = "?" + o.slice(1)),i ? "" + a + o : "" + e + t + a + o);},r = function (e) {var t = document.getElementsByTagName("head")[0],n = document.createElement("script");return ((n.charset = "UTF-8"),(n.src = e),t.appendChild(n),{remove: function () {t.removeChild(n);},});},i = function (e, t, n, i) {return ((t = t || {}),(n = n || !1),new Promise(function (c) {if (n) {var u = setTimeout(function () {clearTimeout(u),l.remove(),c({ code: "0703", msg: "Time out,Refresh Again!" });}, i || 2e3);window["static"] = function () {clearTimeout(u), c.apply(this, arguments), l.remove();};var l = r(e);} else {var s = "VaptchaJsonp" + new Date().valueOf();window[s] && (s += "1"),o(t, { callback: s }),(e = a(e, t));var f = r(e),d = setTimeout(function () {clearTimeout(d),(window[s] = null),f.remove(),c({code: "0703",msg: "Time out,Refresh Again!",});}, 1e4);window[s] = function () {clearTimeout(d),c.apply(this, arguments),f.remove(),(window[s] = null);};}}));};return ((i.setConfig = function (n) {(e = n.protocol || e), (t = n.api_server || t);}),i);})()),S = {staticConfig: function (e) {return T(e.protocol + e.url + e.type + e.id,{},!0,e.waitTime || 2e3);},getConfig: function (e) {var n = "";return (l() &&t(localStorage.getItem("vaptchanu")) &&(n = localStorage.getItem("vaptchanu")),T("/config", {vi: e.vid,t: e.mode,s: e.scene || 0,z: e.zone,v: 3,u: n,}));},lang: function (e) {return T("http://localhost:8080/api/v1/lang", {}, !1);},},C = {en: {"0201": "id empty","0202": "id error","0208": "scene error","0209": "request used up","0906": "params error","0702": "VAPTCHA unit does not match the domain name","0105": "Request too fast, try again later!",},"zh-CN": {"0702": "验证单元与域名不匹配","0105": "刷新过快,请稍后再试。",},},b = 0,j = 9999999999999,I = 0,N = 9999999999999,A = (function () {function r() {var e = navigator.language || navigator.userLanguage;return "zh-CN" === e? "zh-CN": "zh-TW" === e? "zh-TW": e.includes("en", -1)? "en": e.includes("ja", -1)? "jp": "zh-CN";}function i(e) {if ("cn" === e.area) return "cn";if ("sea" === e.area) return "sea";if ("na" === e.area) return (e.area = "sea"), "sea";if (t(localStorage.getItem("vaptchaNetway")) &&"" !== localStorage.getItem("vaptchaNetway"))return (o(e, { area: localStorage.getItem("vaptchaNetway") }),localStorage.getItem("vaptchaNetway"));var n = 0 - new Date().getTimezoneOffset() / 60,a = navigator.language || window.navigator.userLanguage;return ((a = a.toLowerCase()),8 === n && "zh-cn" === a? (o(e, { area: "cn" }), "cn"): 8 === n && "zh-cn" !== a? (o(e, { area: "sea" }), "sea"): (n >= 6 && n < 8) || (n > 8 && n <= 10)? (o(e, { area: "sea" }), "na"): (o(e, { area: "na" }), "na"));}var l = !1,s = function (e) {var n = void 0,a = void 0;return (t(e.area)? ((n = "channel-" + i(e) + ".vaptcha.net/" + i(e)),(a = "api-" + i(e) + ".vaptcha.net")): (o(e, { area: "cn" }),(n = "channel-cn.vaptcha.net/cn"),(a = "api-cn.vaptcha.net")),(b = new Date().getTime()),t(localStorage.getItem("vaptchaSpareCh")) &&new Date().getTime() -localStorage.getItem("vaptchaSpareCh") <36e5? S.staticConfig({protocol: e.protocol,id: e.vid,url: n,type: "/config/",}).then(function (a) {if (((j = new Date().getTime()), w(i(e), e), t(a.alias)))return S.staticConfig({protocol: e.protocol,id: a.alias,url: n,type: "/alias/",}).then(function (e) {return o(e, { state: a.state }), Promise.resolve(e);});console.log("channel error");}): S.staticConfig({protocol: e.protocol,url: a,type: "/channel/",id: e.vid,waitTime: 5e3,}).then(function (a) {return ((j = new Date().getTime()),w(i(e), e),t(a.msg)? (localStorage.setItem("vaptchaSpareCh",new Date().getTime()),S.staticConfig({protocol: e.protocol,id: e.vid,url: n,type: "/config/",}).then(function (a) {if (t(a.alias))return S.staticConfig({protocol: e.protocol,id: a.alias,url: n,type: "/alias/",}).then(function (e) {return (o(e, { state: a.state }),Promise.resolve(e));});console.log("channel error");})): Promise.resolve(a));}));},f = function (e) {return s(e).then(function (n) {if (t(n.code) && "0703" === n.code)return (u("5001: channel interface timeout"),Promise.reject("5001: channel interface timeout"));o(e, { api_server: n.api }), T.setConfig(e);var a = 0 - new Date().getTimezoneOffset() / 60;return o(e, { zone: a }), S.getConfig(e);}).then(function (n) {if (t(n.code) && "0703" === n.code)return (u("5002: config interface timeout"),Promise.reject("5002: config interface timeout"));if (!n) return Promise.resolve();if (n.code !== m.Success) {var a = C.en;return ("0702" === n.msg? alert("" + a[n.msg]): "0105" === n.code? alert("" + a[n.code]): console.log("errorCode:" + n.code + ":" + n.msg),u(a[n.msg] || n.msg),Promise.reject(n.code));}return (n.data.guideVersion && n.data.guideVersion > "3.2.0"? ((n.data.v3Update = 0),console.log("Sorry,the version of V3.JS is too low, please upgrade!")): (n.data.v3Update = 1),o(e, n.data),Promise.resolve());});},d = function (e, t) {return e.protocol + "static-" + e.area + ".vaptcha.net/" + t;},p = function (t) {var n = document.getElementsByTagName("head")[0],a = document.getElementById("vaptcha_style");return new Promise(function (r) {e(a)? ((a = document.createElement("link")),o(a, {rel: "stylesheet",type: "text/css",href: t,id: "vaptcha_style",onload: r,}),n && n.appendChild(a)): r();});},h = function O(e) {var n = document.getElementsByTagName("head")[0],a = document.querySelector("script[src='" + e + "']");return new Promise(function (r) {if (t(a))return void (a.loaded? r(): setTimeout(function () {return O(e).then(r);}));a = document.createElement("script");var i = function () {(a.readyState &&"loaded" !== a.readyState &&"complete" !== a.readyState) ||(r(),(a.loaded = !0),(a.onload = null),(a.onreadystatechange = null));};o(a, {async: !0,charset: "utf-8",src: e,onerror: function () {return u("load sdk timeout");},onload: i,onreadystatechange: i,}),n.appendChild(a);});},y = function (e) {var t = e.sdkName,n = e.config,a = d(n, "js/" + n.js_path);return h(a).then(function () {var e = v(t);return Promise.resolve(new (0, window["_" + e + "Vaptcha"])(n));});},w = function (e, n) {var a = t(localStorage.getItem("vaptchaNetway")),r = t(localStorage.getItem("vaptchaNetwayTime"))? localStorage.getItem("vaptchaNetwayTime"): 0,o = new Date().getTime() - r,i =(t(localStorage.getItem("vaptchaNetwayTime2")) &&localStorage.getItem("vaptchaNetwayTime2"),j - b),c = void 0;if ((i < 500 &&!a &&(localStorage.setItem("vaptchaNetway", e),localStorage.setItem("vaptchaNetwayTime",new Date().getTime()),localStorage.setItem("vaptchaNetwayTime2", i)),!a || i >= 500 || o > 864e5)) {e = e.toLowerCase();var u = void 0;u = "cn" == e ? "sea" : "cn";var l = "api-" + u + ".vaptcha.net";(I = new Date().getTime()),S.staticConfig({protocol: n.protocol,url: l,type: "/channel/",id: n.vid,waitTime: 5e3,}).then(function (t) {(N = new Date().getTime()),(c = N - I),i < c &&(localStorage.setItem("vaptchaNetway", e),localStorage.setItem("vaptchaNetwayTime",new Date().getTime()),localStorage.setItem("vaptchaNetwayTime2", i)),c < i &&(localStorage.setItem("vaptchaNetway", u),localStorage.setItem("vaptchaNetwayTime",new Date().getTime()),localStorage.setItem("vaptchaNetwayTime2", c));});}},A = function (e) {if ("auto" === e.lang || "" === e.lang) {var o = r();e.lang = o || "zh-CN";}(l = !0),(e.https = !0),(e.protocol = "https://"),T.setConfig(e),t(e.type) && (e.mode = e.type),"embedded" === e.mode && (e.mode = "embed"),!["embed", "popup", "invisible"].includes(e.mode) &&(e.mode = "popup"),t(e.mode) && (e.type = e.mode);var i = new g(e);if ((i.addValidateRules({elementOrSelector: function (t, r) {if (("String" === c(e.container) &&(e.container = document.querySelector(e.container)),n(e.container) &&a(e.container[0]) &&(e.container = e.container[0]),!a(e.container)))return r;},}),i.add("vid", "required", "please configure vid"),"invisible" !== e.mode &&i.add("container","elementOrSelector","5004: please configure container with element or selector"),i.validate()))return f(e).then(function () {var t = e.https? "css/theme_https." + e.css_version + ".css": "css/theme." + e.css_version + ".css",n = d(e, t);return p(n);}).then(function () {var t = e.mode;return (l = !1), y({ sdkName: t, config: e });});};return function k(e) {return new Promise(function (t) {l? setTimeout(function () {k(e).then(t);}, 1e3): A(e).then(t);})["catch"](function (e) {return (l = !1), u(e), Promise.reject(e);});};})(),O = (function () {var e = function (e) {var n = e.getAttribute("data-config"),a = {};if (t(n))try {a = JSON.parse(n);} catch (r) {u("dom config format error");}return a;},n = function (e) {var n = e.getAttribute("data-vid");return t(n) ? { vid: n } : {};},a = function (e, n) {var a = Object.create(d);(a.container = e),o(a, n),t(a.vid) &&A(a).then(function (e) {e.renderTokenInput(), e.render();});};return function () {for (var t = document.querySelectorAll("[data-vid]"),r = document.querySelectorAll("[data-config]"),o = 0;o < r.length;o++) {var i = e(r[o]);a(r[o], i);}for (var c = 0; c < t.length; c++)if (!Array.prototype.includes.call(r, t[c])) {var u = n(t[c]);a(t[c], u);}};})();(window.onload = O),(window.vaptcha = function (e) {var t = Object.create(d);return (o(t, e),("auto" === t.lang || "" === t.lang) && (t.lang = f() || "zh-CN"),A(t));});})();</script></head><body><div id="VAPTCHAContainer"><!-- 下面代码为预加载动画代码,仅供参考 --><div class="VAPTCHA-init-main"><div class="VAPTCHA-init-loading"><a href="/" target="_blank"><svgxmlns="http://www.w3.org/2000/svg"xmlns:xlink="http://www.w3.org/1999/xlink"width="48px"height="60px"viewBox="0 0 24 30"style="enable-background: new 0 0 50 50;width: 14px;height: 14px;vertical-align: middle;"xml:space="preserve"><rect x="0" y="9.22656" width="4" height="12.5469" fill="#CCCCCC"><animateattributeName="height"attributeType="XML"values="5;21;5"begin="0s"dur="0.6s"repeatCount="indefinite"></animate><animateattributeName="y"attributeType="XML"values="13; 5; 13"begin="0s"dur="0.6s"repeatCount="indefinite"></animate></rect><rectx="10"y="5.22656"width="4"height="20.5469"fill="#CCCCCC"><animateattributeName="height"attributeType="XML"values="5;21;5"begin="0.15s"dur="0.6s"repeatCount="indefinite"></animate><animateattributeName="y"attributeType="XML"values="13; 5; 13"begin="0.15s"dur="0.6s"repeatCount="indefinite"></animate></rect><rectx="20"y="8.77344"width="4"height="13.4531"fill="#CCCCCC"><animateattributeName="height"attributeType="XML"values="5;21;5"begin="0.3s"dur="0.6s"repeatCount="indefinite"></animate><animateattributeName="y"attributeType="XML"values="13; 5; 13"begin="0.3s"dur="0.6s"repeatCount="indefinite"></animate></rect></svg></a><span class="VAPTCHA-text">Vaptcha Initializing...</span></div></div></div><script>function appCallMethod(key, value) {window[key] = value;}function callAppMethod(method, data = {}) {try {lh.postMessage(JSON.stringify({method,data,}));} catch (error) {}}</script><script>var serverToken = {};var data = {};function getServerToken() {return serverToken;}function getData() {return data;}vaptcha({vid: "65ddaa64d3784602950e7b12",mode: "click",scene: "1",container: "#VAPTCHAContainer",area: "auto",lang: "en",}).then(function (VAPTCHAObj) {// 将VAPTCHA验证实例保存到局部变量中obj = VAPTCHAObj;// 渲染验证组件VAPTCHAObj.render();// 验证成功进行后续操作VAPTCHAObj.listen("pass", function () {serverToken = VAPTCHAObj.getServerToken();data = {server: serverToken.server,token: serverToken.token,scene: (window["scene"] ?? 1) * 1,};callAppMethod("getServerToken", data);});});</script></body>
</html>

最后只需要在接口拦截器中 判断错误状态码 然后主动弹起人机验证

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2815487.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【JavaEE进阶】图书管理系统开发日记——捌

文章目录 &#x1f343;前言&#x1f38d;统一数据返回格式&#x1f6a9;快速入门&#x1f6a9;存在问题&#x1f388;问题原因&#x1f388;代码修改 &#x1f6a9;统一格式返回的优点 &#x1f340;统一异常处理&#x1f332;前端代码的修改&#x1f6a9;登录页面&#x1f6a…

单片机复位按键电路、唤醒按键电路

目录 单片机复位按键 外部手动复位 单片机复位按键电路 复位按键电路1 复位按键电路2 单片机唤醒按键 单片机唤醒按键电路 单片机复位按键 单片机复位&#xff1a;简单来说&#xff0c;复位引脚就是有复位信号&#xff0c;就是从头开始执行程序 本质&#xff1a;就是靠…

NC65 rest接口 开发 NC65接口开发

一、在对应模块META-INF下编写 xxx.rest 文件,也要放在Home里对应的目录下。 二、开发接口&#xff0c;继承extends AbstractUAPRestResource&#xff0c;&#xff08;有的项目会继承别的方法如&#xff1a;AbstractNCCRestResource&#xff0c;MTFRestResource&#xff1b;有…

智能水表预付费管理系统

智能水表预付费管理系统是当前智能水表技术的重要应用之一&#xff0c;结合了智能化管理和预付费功能&#xff0c;为水务公司和用户提供了便捷、高效的用水管理解决方案。该系统利用先进的科技手段&#xff0c;实现了水表抄表、计费和管理的自动化&#xff0c;为用户带来更便捷…

C++ Webserver从零开始:代码书写(十六)——配置文件,服务器,启动!

前言 现在是2024年2月28日的晚上20点36分&#xff0c;我完成了博客的所有内容。现在我整个人有一种如释重负的感觉&#xff0c;今天用webbench测试的时候还闹了个笑话&#xff0c;我在使用测试命令时&#xff0c;url多写了一个http://没注意&#xff0c;导致webbench访问服务器…

基于Python3的数据结构与算法 - 05 堆排序

目录 一、堆排序之树的基础知识 1. 树的定义 2. 树的一些概念 二、堆排序二叉树的基本知识 1. 二叉树的定义 2. 二叉树的存储方式&#xff08;表达方式&#xff09; 2.1 顺序存储方式 三、堆 1. 堆的定义 2. 堆的向下调整性质 四、堆排序的过程 1. 建造堆 五、时…

SpringCloud认识微服务

文章目录 1.1.单体架构1.2.分布式架构1.3.微服务1.4.SpringCloud1.5.总结 随着互联网行业的发展&#xff0c;对服务的要求也越来越高&#xff0c;服务架构也从单体架构逐渐演变为现在流行的微服务架构。这些架构之间有怎样的差别呢&#xff1f; 微服务架构是一种架构模式&…

软考51-上午题-【数据库】-索引

一、索引的定义 在数据库中&#xff0c;索引使得数据库程序无需对整个表进行扫描&#xff0c;就可以在其中找到所需数据。数据库中的索引是某个表中一列或者若干列&#xff0c;值的集合和相应的指向表中物理标识这些值的数据页逻辑指针清单。 二、索引的创建和删除 2-1、索引…

ThreeJS 几何体顶点position、法向量normal及uv坐标

文章目录 几何体的顶点position、法向量normal及uv坐标UV映射UV坐标系UV坐标与顶点坐标设置UV坐标案例1&#xff1a;使用PlaneGeometry创建平面缓存几何体案例2&#xff1a;使用BufferGeometry创建平面缓存几何体 法向量 - 顶点法向量光照计算案例1&#xff1a;不设置顶点法向量…

Linux shell:补充命令的使用

目录 一.导读 二.正文 三.结语 一.导读 上一篇介绍了脚本的简单概念以及使用&#xff0c;现在补充一些命令。 二.正文 目前处于全局目录&#xff0c;通过mkdir创建名我为day01的文件。 通过cd命令day01 切换至day01文件当中。 使用vim文本编辑器文件名&#xff08;firstdir&…

【algorithm】算法基础课---排序算法(附笔记 | 建议收藏)

&#x1f680;write in front&#x1f680; &#x1f4dd;个人主页&#xff1a;认真写博客的夏目浅石. &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd; &#x1f4e3;系列专栏&#xff1a;AcWing算法学习笔记 &#x1f4ac;总结&#xff1a;希望你看完…

day 45 ● 70. 爬楼梯 (进阶)● 322. 零钱兑换 ● 279.完全平方数

#include<bits/stdc.h> using namespace std; int main(){int n,m;cin>>n>>m;vector<int> dp(33,0);dp[0]1;for(int i0;i<n;i){for(int j1;j<m;j){if(i>j)dp[i]dp[i-j];}}// return dp[n];cout<<dp[n]<<endl;} 当然注意 力扣是 …

2.23作业

1.自己实现单向循环链表的功能 //loop_list.c#include"loop_list.h" //创建单向循环链表 loop_p create_head() {loop_p H(loop_p)malloc(sizeof(loop_list));if(HNULL){printf("空间申请失败\n");return NULL;}H->len0;H->nextH;return H; }//创建…

C语言中如何进行内存管理

主页&#xff1a;17_Kevin-CSDN博客 收录专栏&#xff1a;《C语言》 C语言是一种强大而灵活的编程语言&#xff0c;但与其他高级语言不同&#xff0c;它要求程序员自己负责内存的管理。正确的内存管理对于程序的性能和稳定性至关重要。 一、引言 C 语言是一门广泛使用的编程语…

学习Android的第十八天

目录 Android 可复用 BaseAdapter 为什么使用BaseAdapter&#xff1f; 如何使用BaseAdapter&#xff1f; Android GridView 网格视图 GridView 属性 示例 Android Spinner 下拉选项框 Spinner Spinner 属性 示例 Android AutoCompleteTextView 自动完成文本框 Auto…

饲料加工设备让饲料厂和养殖场生产轻松高效

亲爱的饲料厂和养殖场朋友们&#xff0c;你们是不是正在寻找一款方便高效的饲料加工设备呢&#xff1f;那么我们的产品就是你们选择&#xff01; 郑州永兴专为饲料生产而设计的饲料加工设备&#xff0c;无论是养殖场还是饲料厂&#xff0c;都离不开它的帮助。我们提供大中小型…

51单片机-(定时/计数器)

51单片机-&#xff08;定时/计数器&#xff09; 了解CPU时序、特殊功能寄存器和定时/计数器工作原理&#xff0c;以定时器0实现每次间隔一秒亮灯一秒的实验为例理解定时/计数器的编程实现。 1.CPU时序 1.1.四个周期 振荡周期&#xff1a;为单片机提供定时信号的振荡源的周期…

卡尔曼滤波器的定义,实例和代码实现

卡尔曼滤波器(Kalman filter)是一种高效的递归滤波器, 能够从一系列包含噪音的测量值中估计动态系统的状态. 因为不需要存储历史状态, 没有复杂计算, 非常适合在资源有限的嵌入式系统中使用. 常用于飞行器的导引, 导航及控制, 机械和金融中的时间序列分析, 轨迹最佳化等. 卡尔曼…

LeetCode59. 螺旋矩阵 II(C++)

LeetCode59. 螺旋矩阵 II 题目链接代码 题目链接 https://leetcode.cn/problems/spiral-matrix-ii/ 代码 class Solution { public:vector<vector<int>> generateMatrix(int n) {vector<vector<int>> res(n, vector<int>(n, 0));int startx …

Linux第67步_linux字符设备驱动_注册和注销

1、字符设备注册与注销的函数原型” /*字符设备注册的函数原型*/ static inline int register_chrdev(unsigned int major,\ const char *name, \ const struct file_operations *fops) /* major:主设备号&#xff0c;Limnux下每个设备都有一个设备号&#xff0c;设备号分…