最近看滑動驗證碼挺火的,因此就想本身去實驗作一下效果。php
1.去官網申請id和key,註冊進入後臺前端
http://www.geetest.com/web
2.配置前端頁面json
2.1下載jsapi
1 /* initGeetest 1.0.0 2 * 用於加載id對應的驗證碼庫,並支持宕機模式 3 * 暴露 initGeetest 進行驗證碼的初始化 4 * 通常不須要用戶進行修改 5 */ 6 var gtInit =(function (global, factory) { 7 "use strict"; 8 if (typeof module === "object" && typeof module.exports === "object") { 9 // CommonJS 10 module.exports = global.document ? 11 factory(global, true) : 12 function (w) { 13 if (!w.document) { 14 throw new Error("Geetest requires a window with a document"); 15 } 16 return factory(w); 17 }; 18 } else { 19 factory(global); 20 } 21 })(typeof window !== "undefined" ? window : this, function (window, noGlobal) { 22 "use strict"; 23 if (typeof window === 'undefined') { 24 throw new Error('Geetest requires browser environment'); 25 } 26 var document = window.document; 27 var Math = window.Math; 28 var head = document.getElementsByTagName("head")[0]; 29 30 function _Object(obj) { 31 this._obj = obj; 32 } 33 34 _Object.prototype = { 35 _each: function (process) { 36 var _obj = this._obj; 37 for (var k in _obj) { 38 if (_obj.hasOwnProperty(k)) { 39 process(k, _obj[k]); 40 } 41 } 42 return this; 43 } 44 }; 45 function Config(config) { 46 var self = this; 47 new _Object(config)._each(function (key, value) { 48 self[key] = value; 49 }); 50 } 51 52 Config.prototype = { 53 api_server: 'api.geetest.com', 54 protocol: 'http://', 55 type_path: '/gettype.php', 56 fallback_config: { 57 slide: { 58 static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"], 59 type: 'slide', 60 slide: '/static/js/geetest.0.0.0.js' 61 }, 62 fullpage: { 63 static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"], 64 type: 'fullpage', 65 fullpage: '/static/js/fullpage.0.0.0.js' 66 } 67 }, 68 _get_fallback_config: function () { 69 var self = this; 70 if (isString(self.type)) { 71 return self.fallback_config[self.type]; 72 } else if (self.new_captcha) { 73 return self.fallback_config.fullpage; 74 } else { 75 return self.fallback_config.slide; 76 } 77 }, 78 _extend: function (obj) { 79 var self = this; 80 new _Object(obj)._each(function (key, value) { 81 self[key] = value; 82 }) 83 } 84 }; 85 var isNumber = function (value) { 86 return (typeof value === 'number'); 87 }; 88 var isString = function (value) { 89 return (typeof value === 'string'); 90 }; 91 var isBoolean = function (value) { 92 return (typeof value === 'boolean'); 93 }; 94 var isObject = function (value) { 95 return (typeof value === 'object' && value !== null); 96 }; 97 var isFunction = function (value) { 98 return (typeof value === 'function'); 99 }; 100 var callbacks = {}; 101 var status = {}; 102 var random = function () { 103 return parseInt(Math.random() * 10000) + (new Date()).valueOf(); 104 }; 105 var loadScript = function (url, cb) { 106 var script = document.createElement("script"); 107 script.charset = "UTF-8"; 108 script.async = true; 109 script.onerror = function () { 110 cb(true); 111 }; 112 var loaded = false; 113 script.onload = script.onreadystatechange = function () { 114 if (!loaded && 115 (!script.readyState || 116 "loaded" === script.readyState || 117 "complete" === script.readyState)) { 118 119 loaded = true; 120 setTimeout(function () { 121 cb(false); 122 }, 0); 123 } 124 }; 125 script.src = url; 126 head.appendChild(script); 127 }; 128 var normalizeDomain = function (domain) { 129 return domain.replace(/^https?:\/\/|\/$/g, ''); 130 }; 131 var normalizePath = function (path) { 132 path = path.replace(/\/+/g, '/'); 133 if (path.indexOf('/') !== 0) { 134 path = '/' + path; 135 } 136 return path; 137 }; 138 var normalizeQuery = function (query) { 139 if (!query) { 140 return ''; 141 } 142 var q = '?'; 143 new _Object(query)._each(function (key, value) { 144 if (isString(value) || isNumber(value) || isBoolean(value)) { 145 q = q + encodeURIComponent(key) + '=' + encodeURIComponent(value) + '&'; 146 } 147 }); 148 if (q === '?') { 149 q = ''; 150 } 151 return q.replace(/&$/, ''); 152 }; 153 var makeURL = function (protocol, domain, path, query) { 154 domain = normalizeDomain(domain); 155 156 var url = normalizePath(path) + normalizeQuery(query); 157 if (domain) { 158 url = protocol + domain + url; 159 } 160 161 return url; 162 }; 163 var load = function (protocol, domains, path, query, cb) { 164 var tryRequest = function (at) { 165 166 var url = makeURL(protocol, domains[at], path, query); 167 loadScript(url, function (err) { 168 if (err) { 169 if (at >= domains.length - 1) { 170 cb(true); 171 } else { 172 tryRequest(at + 1); 173 } 174 } else { 175 cb(false); 176 } 177 }); 178 }; 179 tryRequest(0); 180 }; 181 var jsonp = function (domains, path, config, callback) { 182 if (isObject(config.getLib)) { 183 config._extend(config.getLib); 184 callback(config); 185 return; 186 } 187 if (config.offline) { 188 callback(config._get_fallback_config()); 189 return; 190 } 191 var cb = "geetest_" + random(); 192 window[cb] = function (data) { 193 if (data.status === 'success') { 194 callback(data.data); 195 } else if (!data.status) { 196 callback(data); 197 } else { 198 callback(config._get_fallback_config()); 199 } 200 window[cb] = undefined; 201 try { 202 delete window[cb]; 203 } catch (e) { 204 } 205 }; 206 load(config.protocol, domains, path, { 207 gt: config.gt, 208 callback: cb 209 }, function (err) { 210 if (err) { 211 callback(config._get_fallback_config()); 212 } 213 }); 214 }; 215 var throwError = function (errorType, config) { 216 var errors = { 217 networkError: '網絡錯誤' 218 }; 219 if (typeof config.onError === 'function') { 220 config.onError(errors[errorType]); 221 } else { 222 throw new Error(errors[errorType]); 223 } 224 }; 225 var detect = function () { 226 return !!window.Geetest; 227 }; 228 if (detect()) { 229 status.slide = "loaded"; 230 } 231 var initGeetest = function (userConfig, callback) { 232 var config = new Config(userConfig); 233 if (userConfig.https) { 234 config.protocol = 'https://'; 235 } else if (!userConfig.protocol) { 236 config.protocol = window.location.protocol + '//'; 237 } 238 jsonp([config.api_server || config.apiserver], config.type_path, config, function (newConfig) { 239 var type = newConfig.type; 240 var init = function () { 241 config._extend(newConfig); 242 callback(new window.Geetest(config)); 243 }; 244 callbacks[type] = callbacks[type] || []; 245 var s = status[type] || 'init'; 246 if (s === 'init') { 247 status[type] = 'loading'; 248 callbacks[type].push(init); 249 load(config.protocol, newConfig.static_servers || newConfig.domains, newConfig[type] || newConfig.path, null, function (err) { 250 if (err) { 251 status[type] = 'fail'; 252 throwError('networkError', config); 253 } else { 254 status[type] = 'loaded'; 255 var cbs = callbacks[type]; 256 for (var i = 0, len = cbs.length; i < len; i = i + 1) { 257 var cb = cbs[i]; 258 if (isFunction(cb)) { 259 cb(); 260 } 261 } 262 callbacks[type] = []; 263 } 264 }); 265 } else if (s === "loaded") { 266 init(); 267 } else if (s === "fail") { 268 throwError('networkError', config); 269 } else if (s === "loading") { 270 callbacks[type].push(init); 271 } 272 }); 273 }; 274 window.initGeetest = initGeetest; 275 return initGeetest; 276 }); 277 278 export default { 279 gtInit 280 }
2.2而後進行引用服務器
1 handleInit(){ 2 let _this=this; 3 api.getCaptcha().then(res => { 4 let { msg, code, data } = res; 5 window.initGeetest({ 6 gt: data.gt, 7 challenge: data.challenge, 8 width:"340px", 9 product: "embed", // 產品形式,包括:float,embed,popup。注意只對PC版驗證碼有效 10 offline: !data.success, // 表示用戶後臺檢測極驗服務器是否宕機,通常不須要關注 11 new_captcha: data.new_captcha 12 }, function(catchaObj){ 13 catchaObj.appendTo("#captcha"); 14 catchaObj.onReady(function(){ 15 document.getElementById('wait').style.display='none'; 16 }); 17 catchaObj.onSuccess(function(){ 18 _this.geetest_challenge=document.getElementsByTagName('input')['geetest_challenge'].value; 19 _this.geetest_validate=document.getElementsByTagName('input')['geetest_validate'].value; 20 _this.geetest_seccode=document.getElementsByTagName('input')['geetest_seccode'].value; 21 }); 22 catchaObj.onError(function(){ 23 console.log('出錯啦,請稍後重試'); 24 }) 25 }) 26 }); 27 },
2.4調用網絡
1 [Route("login")] 2 public class LoginController: ApiController 3 { 4 private IOptions<RecordAccountGeetestOption> _geetestOptions; 5 private ILoggerFactory _loggerFactory; 6 private readonly ILoginService _loginService; 7 public LoginController(ILoginService loginService, IOptions<RecordAccountGeetestOption> geetestOptions, ILoggerFactory loggerFactory) 8 { 9 _loginService = loginService; 10 _geetestOptions = geetestOptions; 11 _loggerFactory = loggerFactory; 12 } 13 14 /// <summary> 15 ///用戶登錄 16 /// </summary> 17 /// <returns></returns> 18 [HttpPost, Route("index")] 19 [NoToken] 20 [ProducesResponseType(typeof(ResponseObjectExtension.ResponseObject<bool>), (int)HttpStatusCode.OK)] 21 public async Task<HttpResponseMessage> IndexAsync([FromBody]LoginRequestDto req) 22 { 23 var validateCode = await ValidateCaptcha(req.GeetestChallenge, req.GeetestValidate, req.GeetestSeccode); 24 if (validateCode == 1) 25 { 26 var user = await _loginService.LoginValidateAsync(req); 27 if (user != null) 28 { 29 var userSession = new CurrentUser 30 { 31 Id = user.Id, 32 Name = user.UserName 33 }; 34 var token = Guid.NewGuid().ToString("N"); 35 RedisHelper.Set(token, userSession, TimeSpan.FromMinutes(60)); 36 return this.Success(token); 37 } 38 return this.Error(ErrCodeCommon.LoginError); 39 } 40 else 41 return this.Error(ErrCodeCommon.ValidateCodeErr); 42 } 43 44 /// <summary> 45 /// 二次進行驗證碼驗證 46 /// </summary> 47 /// <param name="geetestChallenge">本次驗證會話的惟一標識</param> 48 /// <param name="geetestValidate">拖動完成後server端返回的驗證結果標識字符串</param> 49 /// <param name="geetestSeccode">驗證結果的校驗碼,若是gt-server返回的不與這個值相等則代表驗證失敗</param> 50 /// <returns></returns> 51 public async Task<int> ValidateCaptcha(string geetestChallenge,string geetestValidate,string geetestSeccode) 52 { 53 GeetestLib geetest = new GeetestLib(_geetestOptions, _loggerFactory); 54 Byte gt_server_status_code = RedisHelper.Get<Byte>(GeetestLib.gtServerStatusSessionKey); 55 string userID = RedisHelper.Get("captchaUserID").ToString(); 56 string challenge = geetestChallenge; 57 string validate =geetestValidate; 58 string seccode = geetestSeccode; 59 int res = 0; 60 if (gt_server_status_code == 1) 61 res = await geetest.enhencedValidateRequest(challenge, validate, seccode, userID); 62 else 63 res = geetest.failbackValidateRequest(challenge, validate, seccode); 64 return res; 65 } 66 /// <summary> 67 /// 獲取驗證碼 68 /// </summary> 69 /// <returns></returns> 70 [HttpGet, Route("getCaptcha")] 71 public async Task<HttpResponseMessage> getCaptcha() 72 { 73 GeetestLib geetest = new GeetestLib(_geetestOptions, _loggerFactory); 74 string userID = Guid.NewGuid().ToString("N"); 75 //驗證初始化預處理 判斷極驗服務器是否宕機 76 Byte gtServerStatus = await geetest.preProcess(userID, "web", _geetestOptions.Value.IpAddress); 77 //進行存儲 78 RedisHelper.Set("captchaUserID", userID, TimeSpan.FromMinutes(3)); 79 RedisHelper.Set(GeetestLib.gtServerStatusSessionKey, gtServerStatus, TimeSpan.FromMinutes(3)); 80 return this.Success(JsonConvert.DeserializeObject<GeetestResponseHelper>(geetest.getResponseStr())); 81 } 82 }
下面的是涉及到的一些實體和註冊app
public class RecordAccountGeetestOption: GeetestOptions { public string IpAddress { get; set; } }
在startUp.cs註冊
services.Configure<RecordAccountGeetestOption>(Configuration.GetSection(nameof(RecordAccountGeetestOption)));
appsettings.jsondom
"RecordAccountGeetestOption": { "Id": "", "Key": "", "IpAddress": "localhost" },