zoukankan      html  css  js  c++  java
  • 如何在node和vue前后端分离的项目中使用极客验证,用node的方式

    1.用express的脚手架和vue-cli的脚手架搭建的项目目录如下图

    2.在vue-client的src/component新建一个login.vue文件,作为登录页面,代码如下

     1 <template>
     2   <div class="login">
     3     <h1>滑动模式</h1>
     4     <form id="form">
     5         <div>
     6             <label for="username">用户名:</label>
     7             <input class="inp" id="username" type="text" value="用户名">
     8         </div>
     9         <br>
    10         <div>
    11             <label for="password">密码:</label>
    12             <input class="inp" id="password" type="password" value="123456">
    13         </div>
    14         <br>
    15         <div>
    16             <label>完成验证:</label>
    17             <div id="captcha">
    18                 <p id="wait" class="show">正在加载验证码......</p>
    19             </div>
    20         </div>
    21         <br>
    22         <div id="btn" class="btn">提交</div>
    23     </form>
    24   </div>
    25 </template>
    26 
    27 <script>
    28 import jqu from "../../static/js/jquery-2.1.0.js" ; //在验证插件里面有用到jquery方便对节点的操作
    29 import gt from "../../static/js/gt.js" ;//用于加载id对应的验证码库,并支持宕机模式 * 暴露 initGeetest 进行验证码的初始化
    30 import slid from "../../static/js/slider.js" ; //页面对接口的调用
    31 
    32 
    33 
    34 export default {
    35   name: 'login',
    36   data () {
    37     return {
    38       msg: ''
    39     }
    40   }
    41 }
    42 </script>
    43 
    44 <!-- Add "scoped" attribute to limit CSS to this component only -->
    45 <style scoped>
    46   body {
    47             margin: 50px 0;
    48             text-align: center;
    49             font-family: "PingFangSC-Regular", "Open Sans", Arial, "Hiragino Sans GB", "Microsoft YaHei", "STHeiti", "WenQuanYi Micro Hei", SimSun, sans-serif;
    50         }
    51 
    52         .inp {
    53             border: 1px solid #cccccc;
    54             border-radius: 2px;
    55             padding: 0 10px;
    56              278px;
    57             height: 40px;
    58             font-size: 18px;
    59         }
    60 
    61         .btn {
    62             display: inline-block;
    63             box-sizing: border-box;
    64             border: 1px solid #cccccc;
    65             border-radius: 2px;
    66              100px;
    67             height: 40px;
    68             line-height: 40px;
    69             font-size: 16px;
    70             color: #666;
    71             cursor: pointer;
    72             background: white linear-gradient(180deg, #ffffff 0%, #f3f3f3 100%);
    73         }
    74 
    75         .btn:hover {
    76             background: white linear-gradient(0deg, #ffffff 0%, #f3f3f3 100%)
    77         }
    78 
    79         #captcha {
    80              300px;
    81             display: inline-block;
    82         }
    83 
    84         label {
    85             vertical-align: top;
    86             display: inline-block;
    87              80px;
    88             text-align: right;
    89         }
    90 
    91         #wait {
    92             text-align: left;
    93             color: #666;
    94             margin: 0;
    95         }
    96 </style>
    View Code

    3.这里是gt.js,放在static/js文件夹下面

      1 /* initGeetest 1.0.0
      2  * 用于加载id对应的验证码库,并支持宕机模式
      3  * 暴露 initGeetest 进行验证码的初始化
      4  * 一般不需要用户进行修改
      5  */
      6 (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 });
    View Code

    4.下面是slider.js,也是放在static/js文件夹下面(使用中只用改动两个接口的地址,和自己写的后台地址对应上)

     1  var handler = function (captchaObj) {
     2         captchaObj.appendTo('#captcha');
     3         captchaObj.onReady(function () {
     4             $("#wait").hide();
     5         });
     6         $('#btn').click(function () {
     7             var result = captchaObj.getValidate();
     8             if (!result) {
     9                 return alert('请完成验证');
    10             }
    11             $.ajax({
    12                 url: 'http://localhost:3000/gt/validate-slide', //这里的地址是根据你的后台接口的地址,我这里是这样的
    13                 type: 'POST',
    14                 dataType: 'json',
    15                 data: {
    16                     geetest_challenge: result.geetest_challenge,
    17                     geetest_validate: result.geetest_validate,
    18                     geetest_seccode: result.geetest_seccode
    19                 },
    20                 success: function (data) {
    21                     if (data.status === 'success') {
    22                         alert('登录成功');
    23                     } else if (data.status === 'fail') {
    24                         alert('登录失败,请完成验证');
    25                         captchaObj.reset();
    26                     }
    27                 }
    28             });
    29         })
    30         // 更多接口说明请参见:http://docs.geetest.com/install/client/web-front/
    31     };
    32 
    33 
    34     $.ajax({//这个地址也是需要根据自己的后台接口地址来改动
    35         url: "http://localhost:3000/gt/register-slide?t=" + (new Date()).getTime(), // 加随机数防止缓存
    36         type: "get",
    37         dataType: "json",
    38         success: function (data) {
    39                 console.log(data)
    40             // 调用 initGeetest 进行初始化
    41             // 参数1:配置参数
    42             // 参数2:回调,回调的第一个参数验证码对象,之后可以使用它调用相应的接口
    43 
    44             initGeetest({
    45                 // 以下 4 个配置参数为必须,不能缺少
    46                 gt: data.gt,
    47                 challenge: data.challenge,
    48                 offline: !data.success, // 表示用户后台检测极验服务器是否宕机
    49                 new_captcha: data.new_captcha, // 用于宕机时表示是新验证码的宕机
    50 
    51                 product: "float", // 产品形式,包括:float,popup
    52                  "300px"
    53                 // 更多配置参数说明请参见:http://docs.geetest.com/install/client/web-front/
    54             }, handler);
    55         }
    56     });
    View Code

    5.后台的配置,在serviceget文件夹的主入口文件app.js中插入验证的接口处理;

      1 var express = require('express');
      2 var path = require('path');
      3 var favicon = require('serve-favicon');
      4 var logger = require('morgan');
      5 var cookieParser = require('cookie-parser');
      6 var bodyParser = require('body-parser');
      7 
      8 var index = require('./routes/index');
      9 var users = require('./routes/users');
     10 
     11 
     12 /*这里引入极客验证的包 */
     13 var Geetest = require('gt3-sdk');
     14 var slide = require('./public/javascripts/slide');
     15 
     16 var app = express();
     17 
     18 
     19 //实现跨域
     20 app.all('*',function(req,res,next){
     21     res.header('Access-Control-Allow-Origin','http://localhost:8081');
     22     res.header('Access-Control-Allow-Methods','PUT,GET,POST,DELETE,OPTIONS');
     23     res.header('Access-Control-Allow-Headers','X-Requested-With');
     24     res.header('Access-Control-Allow-Headers','Content-Type');
     25     res.header('Access-Control-Allow-Credentials',true);
     26     next();
     27 })
     28 
     29 //session,需要引用下面的包
     30 var session = require('express-session');
     31 app.use(session({
     32     secret: 'classweb531234', //设置 session 签名
     33     name: 'classweb',
     34     cookie: {
     35         maxAge: 60 * 1000 * 60 * 24
     36     }, // 储存的时间 24小时
     37     resave: false, // 每次请求都重新设置session
     38     saveUninitialized: true
     39 }));
     40 
     41 
     42 
     43 //极客验证
     44 app.get("/gt/register-slide", function (req, res) {
     45   slide.register(null, function (err, data) {
     46       if (err) {
     47           console.error(err);
     48           res.status(500);
     49           res.send(err);
     50           return;
     51       }
     52 
     53       if (!data.success) {
     54           req.session.fallback = true;
     55           res.send(data);
     56       } else {
     57           req.session.fallback = false;
     58           res.send(data);
     59       }
     60   });
     61 });
     62 
     63 
     64 
     65 
     66 // view engine setup
     67 app.set('views', path.join(__dirname, 'views'));
     68 app.set('view engine', 'jade');
     69 
     70 // uncomment after placing your favicon in /public
     71 //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
     72 app.use(logger('dev'));
     73 app.use(bodyParser.json());
     74 app.use(bodyParser.urlencoded({ extended: false }));
     75 app.use(cookieParser());
     76 app.use(express.static(path.join(__dirname, 'public')));
     77 
     78 //极客验证的二次验证,这里可以对用户名,和密码验证
     79 //这里用了req.body所以要放在bodyparser中间件申明后的地方
     80 app.post("/gt/validate-slide", function (req, res) {
     81   // 对ajax提供的验证凭证进行二次验证
     82   slide.validate(req.session.fallback, {
     83       geetest_challenge: req.body.geetest_challenge,
     84       geetest_validate: req.body.geetest_validate,
     85       geetest_seccode: req.body.geetest_seccode
     86   }, function (err, success) {
     87 
     88       if (err) {
     89           // 网络错误
     90           res.send({
     91               status: "error",
     92               info: err
     93           });
     94 
     95       } else if (!success) {
     96 
     97           // 二次验证失败
     98           res.send({
     99               status: "fail",
    100               info: '登录失败'
    101           });
    102       } else {
    103 
    104           res.send({
    105               status: "success",
    106               info: '登录成功'
    107           });
    108       }
    109   });
    110 });
    111 
    112 
    113 
    114 
    115 
    116 
    117 app.use('/', index);
    118 app.use('/users', users);
    119 
    120 // catch 404 and forward to error handler
    121 app.use(function(req, res, next) {
    122   var err = new Error('Not Found');
    123   err.status = 404;
    124   next(err);
    125 });
    126 
    127 // error handler
    128 app.use(function(err, req, res, next) {
    129   // set locals, only providing error in development
    130   res.locals.message = err.message;
    131   res.locals.error = req.app.get('env') === 'development' ? err : {};
    132 
    133   // render the error page
    134   res.status(err.status || 500);
    135   res.render('error');
    136 });
    137 
    138 module.exports = app;
    View Code

      

    6.在后台serviceget/public/javascripts 文件夹下面复制进gt-sdk.js 和slide.js(gt-sdk.js是对sdk包的处理,slide.js是保存的自己的密钥,和对gt-sdk.js方法的引用)

    gt-sdk.js代码如下:

      1 "use strict";
      2 var crypto = require('crypto'),
      3     request = require('request'),
      4     pkg = require("../../package.json");  //这个地方地址根据自己文件位置来找,找到package.json的相对路径
      5 
      6 var md5 = function (str) {
      7     return crypto.createHash('md5').update(String(str)).digest('hex');
      8 };
      9 var randint = function (from, to) {
     10     // range: from ~ to
     11     return Math.floor(Math.random() * (to - from + 1) + from);
     12 };
     13 function Geetest(config) {
     14     if (typeof config.geetest_id !== 'string') {
     15         throw new Error('Geetest ID Required');
     16     }
     17     if (typeof config.geetest_key !== 'string') {
     18         throw new Error("Geetest KEY Required");
     19     }
     20     if (typeof config.protocol === 'string') {
     21         this.PROTOCOL = config.protocol;
     22     }
     23     if (typeof config.api_server === 'string') {
     24         this.API_SERVER = config.api_server;
     25     }
     26     if (typeof config.timeout === 'number') {
     27         this.TIMEOUT = config.timeout;
     28     }
     29 
     30     this.geetest_id = config.geetest_id;
     31     this.geetest_key = config.geetest_key;
     32 }
     33 Geetest.prototype = {
     34     PROTOCOL: 'http://',
     35     API_SERVER: 'api.geetest.com',
     36     VALIDATE_PATH: '/validate.php',
     37     REGISTER_PATH: '/register.php',
     38     TIMEOUT: 2000,
     39     NEW_CAPTCHA: true,
     40     JSON_FORMAT: 1,
     41     register: function (data, callback) {
     42         var that = this;
     43         return new Promise(function (resolve, reject) {
     44             that._register(data, function (err, data) {
     45                 if (typeof callback === 'function') {
     46                     callback(err, data);
     47                 }
     48                 if (err) {
     49                     reject(err);
     50                 } else {
     51                     resolve(data);
     52                 }
     53             });
     54         });
     55     },
     56     _register: function (data, callback) {
     57         data = data || {};
     58         var that = this;
     59         request({
     60             url: this.PROTOCOL + this.API_SERVER + this.REGISTER_PATH,
     61             method: 'GET',
     62             timeout: this.TIMEOUT,
     63             json: true,
     64             qs: {
     65                 gt: this.geetest_id,
     66                 json_format: this.JSON_FORMAT,
     67                 sdk: 'Node_' + pkg.version,
     68                 client_type: data.client_type || 'unknown',
     69                 ip_address: data.ip_address || 'unknown'
     70             }
     71         }, function (err, res, data) {
     72             var challenge;
     73             if (err || !data || !data.challenge) {
     74                 // fallback
     75                 challenge = that._make_challenge();
     76                 callback(null, {
     77                     success: 0,
     78                     challenge: challenge,
     79                     gt: that.geetest_id,
     80                     new_captcha: that.NEW_CAPTCHA
     81                 });
     82             } else {
     83                 challenge = md5(data.challenge + that.geetest_key);
     84                 callback(null, {
     85                     success: 1,
     86                     challenge: challenge,
     87                     gt: that.geetest_id,
     88                     new_captcha: that.NEW_CAPTCHA
     89                 });
     90             }
     91         });
     92     },
     93     validate: function (fallback, result, callback) {
     94         var that = this;
     95         return new Promise(function (resolve, reject) {
     96             that._validate(fallback, result, function (err, data) {
     97                 if (typeof callback === 'function') {
     98                     callback(err, data);
     99                 }
    100                 if (err) {
    101                     reject(err);
    102                 } else {
    103                     resolve(data);
    104                 }
    105             });
    106         })
    107     },
    108     _validate: function (fallback, result, callback) {
    109         var challenge = result.challenge || result.geetest_challenge;
    110         var validate = result.validate || result.geetest_validate;
    111         var seccode = result.seccode || result.geetest_seccode;
    112         if (fallback) {
    113             if (md5(challenge) === validate) {
    114                 callback(null, true);
    115             } else {
    116                 callback(null, false);
    117             }
    118         } else {
    119             var hash = this.geetest_key + 'geetest' + challenge;
    120             if (validate === md5(hash)) {
    121                 request({
    122                     url: this.PROTOCOL + this.API_SERVER + this.VALIDATE_PATH,
    123                     method: 'POST',
    124                     timeout: this.TIMEOUT,
    125                     json: true,
    126                     form: {
    127                         gt: this.geetest_id,
    128                         seccode: seccode,
    129                         json_format: this.JSON_FORMAT
    130                     }
    131                 }, function (err, res, data) {
    132                     if (err || !data || !data.seccode) {
    133                         callback(err);
    134                     } else {
    135                         callback(null, data.seccode === md5(seccode));
    136                     }
    137                 });
    138             } else {
    139                 callback(null, false);
    140             }
    141         }
    142     },
    143     _make_challenge: function () {
    144         var rnd1 = randint(0, 90);
    145         var rnd2 = randint(0, 90);
    146         var md5_str1 = md5(rnd1);
    147         var md5_str2 = md5(rnd2);
    148         return md5_str1 + md5_str2.slice(0, 2);
    149     }
    150 };
    151 
    152 module.exports = Geetest;
    View Code

    slide.js代码如下:

    var Geetest = require('./gt-sdk');
    var captcha = new Geetest({
        geetest_id: '***************************', //注册极客获得的id
        geetest_key: '**************************'  //注册极客获得的key
    });
    
    module.exports = captcha;

    7.效果图如下面:

  • 相关阅读:
    Linux-Zabbix 邮件报警设置
    CentOS6.7 防火墙规则(Iptables)
    CentOS7 防火墙规则 (firewalld)
    windows搭建代理服务器
    Linux服务器的远程IP限制
    利用shell脚本监控目录内文件改动
    CentOS 7, 升级python到3.x
    CentOS 7, Attempting to create directory /root/perl5
    变长参数表
    C语言预处理
  • 原文地址:https://www.cnblogs.com/chun321/p/8818746.html
Copyright © 2011-2022 走看看