最近看滑动验证码挺火的,所以就想自己去实验做一下效果。
1.去官网申请id和key,注册进入后台
http://www.geetest.com/
2.配置前端页面
2.1下载js
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: cb209 }, 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 gtInit280 }
2.2然后进行引用
显示验证码的地方
<el-form-item>
<div id="captcha"></div>
<el-alert
id="wait"
class="show"
title="正在加载验证码......"
type="success">
</el-alert>
</el-form-item>
import gtInit from '../common/js/gt'
定义三个参数用来后续传到服务器进行验证
geetest_challenge:'',
geetest_validate:'',
geetest_seccode:'',
2.3定义一个方法用来初始化
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_captcha12 }, 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 },
api.getCaptcha()调用的接口
API.get('/login/getCaptcha?t='+(new Date()).getTime(), params)
2.4调用
created(){
this.handleInit();
}
服务器控制器接口
1 [Route("login")] 2 public class LoginController: ApiController 3 { 4 private IOptions_geetestOptions; 5 private ILoggerFactory _loggerFactory; 6 private readonly ILoginService _loginService; 7 public LoginController(ILoginService loginService, IOptions geetestOptions, ILoggerFactory loggerFactory) 8 { 9 _loginService = loginService;10 _geetestOptions = geetestOptions;11 _loggerFactory = loggerFactory;12 }13 14 /// 15 ///用户登陆16 /// 17 ///18 [HttpPost, Route("index")]19 [NoToken]20 [ProducesResponseType(typeof(ResponseObjectExtension.ResponseObject ), (int)HttpStatusCode.OK)]21 public async Task 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 CurrentUser30 {31 Id = user.Id,32 Name = user.UserName33 };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 else41 return this.Error(ErrCodeCommon.ValidateCodeErr);42 }43 44 /// 45 /// 二次进行验证码验证46 /// 47 /// 本次验证会话的唯一标识48 /// 拖动完成后server端返回的验证结果标识字符串49 /// 验证结果的校验码,如果gt-server返回的不与这个值相等则表明验证失败50 ///51 public async Task ValidateCaptcha(string geetestChallenge,string geetestValidate,string geetestSeccode)52 {53 GeetestLib geetest = new GeetestLib(_geetestOptions, _loggerFactory);54 Byte gt_server_status_code = RedisHelper.Get (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 else63 res = geetest.failbackValidateRequest(challenge, validate, seccode);64 return res;65 }66 /// 67 /// 获取验证码68 /// 69 ///70 [HttpGet, Route("getCaptcha")]71 public async Task 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 (geetest.getResponseStr()));81 }82 }
下面的是涉及到的一些实体和注册
public class RecordAccountGeetestOption: GeetestOptions { public string IpAddress { get; set; } }
在startUp.cs注册 services.Configure(Configuration.GetSection(nameof(RecordAccountGeetestOption)));
appsettings.json
"RecordAccountGeetestOption": { "Id": "", "Key": "", "IpAddress": "localhost" },
posted on 2018-09-18 16:59 阅读( ...) 评论( ...)