zoukankan      html  css  js  c++  java
  • 手写一个仿微信登录的Nodejs程序

    前言

    首先,我们看一下微信开放文档中的一张图:

    上面的一幅图中清楚地介绍了微信登录整个过程,下面对图上所示进行总结:

    一、二维码的获得

    用户打开登录网页后,登录网页后台根据微信OAuth2.0协议向微信开发平台请求授权登录,并传递事先在微信开发平台中审核通过的AppID和AppSecrect等参数;

    微信开发平台对AppID等参数进行验证,并向登录网页后台返回二维码;

    登录网页后台将二维码传送至前台进行显示;

    二、微信客户端授权登录

    用户使用微信客户端扫描二维码并授权登录;

    微信客户端将二维码特定的uid与微信账号绑定,传送至微信开发平台;

    微信开发平台验证绑定数据,调用登录网页后台的回调接口,发送授权临时票据code;

    三、网页后台请求数据

    登录网页后台接收到code,表明微信开发平台同意数据请求;

    登录网页后台根据code参数,再加上AppID和AppSecret请求微信开发平台换取access_token;

    微信开发平台验证参数,并返回access_token;

    登录网页后台收到access_token后即可进行参数分析获得用户账号数据。

    https://www.houdianzi.com/ logo设计公司

    实现

    了解了大致原理之后,我们就开始简单实现这个逻辑。因为没有直接调用微信开发平台,所以这里只是演示效果。你也可以通过访问:

    https://www.maomin.club/qrcodelogin/ 
    

    这个我的线上网址体验一下。以下代码是主要逻辑,结合线上网址体验更容易理解。

    let http = require("http"); 
    let express = require("express"); 
    let qrcode = require("qr-image"); 
    let app = express(); 
    let path = require("path"); 
    let server = http.createServer(app); 
    let url = require("url"); 
    let fs = require("fs"); 
    let UUID = require("uuid-js"); 
    let generatehtml = null; 
     
    app.use(express.static("./public")); 
     
    /* 
     * Description: 读取网页文件,用于替换关键字,相当于简易模板 
     * Params: 
     * sessionID - 生成的uid 
     * req - 网页请求 
     * res - 网页应答 
     * fileName - 网页文件所在路径 
     */ 
    generatehtml = function (sessionID, req, res, fileName) { 
      fs.readFile(fileName, "UTF-8", function (err, data) { 
        if (!err) { 
          data = data.replace(/SESSION_UID/g, sessionID); 
          res.writeHead(200, { 
            "Content-Type": "text/html; charset=UTF-8", 
          }); 
          res.end(data); 
        } else { 
          console.log(err); 
     
          res.writeHead(404, { 
            "Content-Type": "text/html; charset=UTF-8", 
          }); 
          res.end(); 
        } 
      }); 
    }; 
     
    /* 
     * Description: 写入jsON文件 
     * Params: 
     * fileName - JSON文件所在路径 
     * uid - 生成的uid 
     * writeData - 需要写入的JSON格式数据 
     * 
     */ 
    let setJSONValue = function (fileName, uid, writeData) { 
      let data = fs.readFileSync(fileName); 
     
      let users = JSON.parse(data.toString()); 
      let addFlag = true; 
      let delFlag = writeData === null; 
     
      for (let i = 0; i < users.data.length; i++) { 
        if (users.data[i].uid === uid) { 
          addFlag = false; 
     
          if (delFlag) { 
            users.data.splice(i, 1); 
          } else { 
            users.data[i].status = writeData.status; 
     
            console.log( 
              "writeJSON: " + JSON.stringify(users.data[i]) + " modified." 
            ); 
          } 
        } 
      } 
     
      if (addFlag) { 
        users.data.push(writeData); 
        console.log("writeJSON: " + JSON.stringify(writeData) + " inserted."); 
      } 
     
      // 同步写入文件 
      let writeJSON = JSON.stringify(users); 
      fs.writeFileSync(fileName, writeJSON); 
    }; 
     
    /* 
     * Description: 读取JSON文件(要返回数据,选择同步读取) 
     * Params: 
     * fileName - JSON文件所在路径 
     * uid - 生成的uid 
     * 
     */ 
    getJSONValue = function (fileName, uid) { 
      let readData = null; 
     
      // 同步读取文件 
      let data = fs.readFileSync(fileName); 
     
      let users = JSON.parse(data.toString()); 
     
      for (let i = 0; i < users.data.length; i++) { 
        if (users.data[i].uid === uid) { 
          readData = JSON.stringify(users.data[i]); 
          break; 
        } 
      } 
     
      return readData; 
    }; 
     
    // 显示网站首页 
    app.get("/", function (req, res) { 
      // 生成唯一的ID 
      let uid = UUID.create(); 
      console.log("uid: '" + uid + "' generated."); 
      // 替换网页模板内的UID关键字 
      generateHTML(uid, req, res, path.join(__dirname, "/views/main.html")); 
    }); 
     
    // 生成二维码图片并显示 
    app.get("/qrcode", function (req, res, next) { 
      let uid = url.parse(req.url, true).query.uid; 
     
      try { 
        if (typeof uid !== "undefined") { 
          // 写入二维码内的网址,微信扫描后自动跳转。下面的网址是我的网址,https://www.maomin.club/qrcodelogin ,你可以换成自己的线上网址或者本地服务器。加上后面的"/scanned?uid=" 
          let jumpURL = "https://www.maomin.club/qrcodelogin/scanned?uid=" + uid; 
          // 生成二维码(size:图片大小, margin: 边框留白) 
          let img = qrcode.image(jumpURL, { size: 6, margin: 2 }); 
          res.writeHead(200, { "Content-Type": "image/png" }); 
          img.pipe(res); 
        } else { 
          res.writeHead(414, { "Content-Type": "text/html" }); 
          res.end("<h1>414 Request-URI Too Large</h1>"); 
        } 
      } catch (e) { 
        res.writeHead(414, { "Content-Type": "text/html" }); 
        res.end("<h1>414 Request-URI Too Large</h1>"); 
      } 
    }); 
     
    // 显示手机扫描后的确认界面 
    app.get("/scanned", function (req, res) { 
      let uid = url.parse(req.url, true).query.uid; 
     
      if (typeof uid !== "undefined") { 
        generateHTML(uid, req, res, path.join(__dirname, "/views/confirm.html")); 
     
        console.log("uid: '" + uid + "' scanned."); 
     
        // 获取JSON文件内对应uid的数据,更改其数据状态 
        let jsonData = getJSONValue(path.join(__dirname, "/bin/data.json"), uid); 
     
        if (jsonData === null) { 
          jsonData = { 
            uid: uid, 
            status: "scanned", 
            name: "USER", 
          }; 
        } else { 
          jsonData = JSON.parse(jsonData); 
          jsonData.status = "scanned"; 
        } 
     
        // 写入JSON文件 
        setJSONValue(path.join(__dirname, "/bin/data.json"), uid, jsonData); 
      } else { 
        res.writeHead(414, { "Content-Type": "text/html" }); 
        res.end("<h1>414 Request-URI Too Large</h1>"); 
      } 
    }); 
     
    // 在确认界面操作的响应 
    app.get("/confirmed", function (req, res) { 
      let uid = url.parse(req.url, true).query.uid; 
      let operate = url.parse(req.url, true).query.operate; 
     
      if (typeof uid !== "undefined") { 
        console.log("uid: '" + uid + "' " + operate); 
     
        let jsonData = getJSONValue(path.join(__dirname, "/bin/data.json"), uid); 
        let status = operate === "confirm" ? "verified" : "canceled"; 
     
        if (jsonData === null) { 
          jsonData = { 
            uid: uid, 
            status: status, 
            name: "USER", 
          }; 
        } else { 
          jsonData = JSON.parse(jsonData); 
          jsonData.status = status; 
        } 
     
        setJSONValue(path.join(__dirname, "/bin/data.json"), uid, jsonData); 
     
        if (status === "verified") { 
          res.writeHead(200, { "Content-Type": "text/html" }); 
          res.end("<h1>登录成功!</h1>"); 
        } else { 
          res.writeHead(200, { "Content-Type": "text/html" }); 
          res.end("<h1>Canceled!</h1>"); 
        } 
      } else { 
        res.writeHead(414, { "Content-Type": "text/html" }); 
        res.end("<h1>414 Request-URI Too Large</h1>"); 
      } 
    }); 
     
    // 响应主页不断的AJAX请求 
    app.get("/verified", function (req, res) { 
      let uid = url.parse(req.url, true).query.uid; 
     
      // normal   - 没有任何触发 
      // scanned  - 已扫描 
      // canceled - 已取消 
      // verified - 已验证 
      let dataStatus = { 
        cmd: "normal", 
        user: "", 
      }; 
     
      console.log("uid: '" + uid + "' query ..."); 
     
      if (typeof uid !== "undefined") { 
        let userData = getJSONValue(path.join(__dirname, "/bin/data.json"), uid); 
     
        // 返回JSON数据用于首页AJAX操作 
        if (userData !== null) { 
          userData = JSON.parse(userData); 
          dataStatus.cmd = userData.status; 
          dataStatus.user = userData.name; 
        } 
      } 
     
      res.end(JSON.stringify(dataStatus)); 
    }); 
     
    server.listen(4000); 
    console.log( 
      "Express server listening on port %d in %s mode", 
      server.address().port, 
      app.settings.env 
    ); 
  • 相关阅读:
    信用卡知识:自动扣款日不等于最后还款日_刷卡技巧_财经_腾讯网
    北京,大兴,采育,京福路边上。嘿嘿,交通还是很便利的。
    想知道:北京市 亦庄交通队在哪?
    bda_百度百科
    聚合服务资费标准
    公租自行车-北京经济技术开发区
    北京公共自行车-北京市交通委员会运输管理局
    北京公共自行车租赁方法_百度知道
    NEXT | 不错过任何一个新产品
    吸血鬼日记 第五季 16 | 美剧单词
  • 原文地址:https://www.cnblogs.com/qianxiaox/p/15149684.html
Copyright © 2011-2022 走看看