12

手写一个仿微信登录的Nodejs程序

 3 years ago
source link: http://network.51cto.com/art/202012/634624.htm
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

手写一个仿微信登录的Nodejs程序

本篇教你手写一个仿微信登录的Nodejs程序,希望对你有所帮助。

作者:maomin9761来源:前端历劫之路|2020-12-13 11:57

 前言

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

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

一、二维码的获得

  1. 用户打开登录网页后,登录网页后台根据微信OAuth2.0协议向微信开发平台请求授权登录,并传递事先在微信开发平台中审核通过的AppID和AppSecrect等参数;
  2. 微信开发平台对AppID等参数进行验证,并向登录网页后台返回二维码;
  3. 登录网页后台将二维码传送至前台进行显示;

二、微信客户端授权登录

  1. 用户使用微信客户端扫描二维码并授权登录;
  2. 微信客户端将二维码特定的uid与微信账号绑定,传送至微信开发平台;
  3. 微信开发平台验证绑定数据,调用登录网页后台的回调接口,发送授权临时票据code;

三、网页后台请求数据

  1. 登录网页后台接收到code,表明微信开发平台同意数据请求;
  2. 登录网页后台根据code参数,再加上AppID和AppSecret请求微信开发平台换取access_token;
  3. 微信开发平台验证参数,并返回access_token;
  4. 登录网页后台收到access_token后即可进行参数分析获得用户账号数据。

实现

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

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

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

  1. let http = require("http"); 
  2. let express = require("express"); 
  3. let qrcode = require("qr-image"); 
  4. let app = express(); 
  5. let path = require("path"); 
  6. let server = http.createServer(app); 
  7. let url = require("url"); 
  8. let fs = require("fs"); 
  9. let UUID = require("uuid-js"); 
  10. let generateHTML = null; 
  11. app.use(express.static("./public")); 
  12.  * Description: 读取网页文件,用于替换关键字,相当于简易模板 
  13.  * Params: 
  14.  * sessionID - 生成的uid 
  15.  * req - 网页请求 
  16.  * res - 网页应答 
  17.  * fileName - 网页文件所在路径 
  18. generateHTML = function (sessionID, req, res, fileName) { 
  19.   fs.readFile(fileName, "UTF-8", function (err, data) { 
  20.     if (!err) { 
  21.       data = data.replace(/SESSION_UID/g, sessionID); 
  22.       res.writeHead(200, { 
  23.         "Content-Type": "text/html; charset=UTF-8", 
  24.       res.end(data); 
  25.     } else { 
  26.       console.log(err); 
  27.       res.writeHead(404, { 
  28.         "Content-Type": "text/html; charset=UTF-8", 
  29.       res.end(); 
  30.  * Description: 写入JSON文件 
  31.  * Params: 
  32.  * fileName - JSON文件所在路径 
  33.  * uid - 生成的uid 
  34.  * writeData - 需要写入的JSON格式数据 
  35. let setJSONValue = function (fileName, uid, writeData) { 
  36.   let data = fs.readFileSync(fileName); 
  37.   let users = JSON.parse(data.toString()); 
  38.   let addFlag = true; 
  39.   let delFlag = writeData === null; 
  40.   for (let i = 0; i < users.data.length; i++) { 
  41.     if (users.data[i].uid === uid) { 
  42.       addFlag = false; 
  43.       if (delFlag) { 
  44.         users.data.splice(i, 1); 
  45.       } else { 
  46.         users.data[i].status = writeData.status; 
  47.         console.log( 
  48.           "writeJSON: " + JSON.stringify(users.data[i]) + " modified." 
  49.   if (addFlag) { 
  50.     users.data.push(writeData); 
  51.     console.log("writeJSON: " + JSON.stringify(writeData) + " inserted."); 
  52.   // 同步写入文件 
  53.   let writeJSON = JSON.stringify(users); 
  54.   fs.writeFileSync(fileName, writeJSON); 
  55.  * Description: 读取JSON文件(要返回数据,选择同步读取) 
  56.  * Params: 
  57.  * fileName - JSON文件所在路径 
  58.  * uid - 生成的uid 
  59. getJSONValue = function (fileName, uid) { 
  60.   let readData = null; 
  61.   // 同步读取文件 
  62.   let data = fs.readFileSync(fileName); 
  63.   let users = JSON.parse(data.toString()); 
  64.   for (let i = 0; i < users.data.length; i++) { 
  65.     if (users.data[i].uid === uid) { 
  66.       readData = JSON.stringify(users.data[i]); 
  67.       break; 
  68.   return readData; 
  69. // 显示网站首页 
  70. app.get("/", function (req, res) { 
  71.   // 生成唯一的ID 
  72.   let uid = UUID.create(); 
  73.   console.log("uid: '" + uid + "' generated."); 
  74.   // 替换网页模板内的UID关键字 
  75.   generateHTML(uid, req, res, path.join(__dirname, "/views/main.html")); 
  76. // 生成二维码图片并显示 
  77. app.get("/qrcode", function (req, res, next) { 
  78.   let uid = url.parse(req.url, true).query.uid; 
  79.     if (typeof uid !== "undefined") { 
  80.       // 写入二维码内的网址,微信扫描后自动跳转。下面的网址是我的网址,https://www.maomin.club/qrcodelogin ,你可以换成自己的线上网址或者本地服务器。加上后面的"/scanned?uid=" 
  81.       let jumpURL = "https://www.maomin.club/qrcodelogin/scanned?uid=" + uid; 
  82.       // 生成二维码(size:图片大小, margin: 边框留白) 
  83.       let img = qrcode.image(jumpURL, { size: 6, margin: 2 }); 
  84.       res.writeHead(200, { "Content-Type": "image/png" }); 
  85.       img.pipe(res); 
  86.     } else { 
  87.       res.writeHead(414, { "Content-Type": "text/html" }); 
  88.       res.end("<h1>414 Request-URI Too Large</h1>"); 
  89.   } catch (e) { 
  90.     res.writeHead(414, { "Content-Type": "text/html" }); 
  91.     res.end("<h1>414 Request-URI Too Large</h1>"); 
  92. // 显示手机扫描后的确认界面 
  93. app.get("/scanned", function (req, res) { 
  94.   let uid = url.parse(req.url, true).query.uid; 
  95.   if (typeof uid !== "undefined") { 
  96.     generateHTML(uid, req, res, path.join(__dirname, "/views/confirm.html")); 
  97.     console.log("uid: '" + uid + "' scanned."); 
  98.     // 获取JSON文件内对应uid的数据,更改其数据状态 
  99.     let jsonData = getJSONValue(path.join(__dirname, "/bin/data.json"), uid); 
  100.     if (jsonData === null) { 
  101.       jsonData = { 
  102.         uid: uid, 
  103.         status: "scanned", 
  104.         name: "USER", 
  105.     } else { 
  106.       jsonData = JSON.parse(jsonData); 
  107.       jsonData.status = "scanned"; 
  108.     // 写入JSON文件 
  109.     setJSONValue(path.join(__dirname, "/bin/data.json"), uid, jsonData); 
  110.   } else { 
  111.     res.writeHead(414, { "Content-Type": "text/html" }); 
  112.     res.end("<h1>414 Request-URI Too Large</h1>"); 
  113. // 在确认界面操作的响应 
  114. app.get("/confirmed", function (req, res) { 
  115.   let uid = url.parse(req.url, true).query.uid; 
  116.   let operate = url.parse(req.url, true).query.operate; 
  117.   if (typeof uid !== "undefined") { 
  118.     console.log("uid: '" + uid + "' " + operate); 
  119.     let jsonData = getJSONValue(path.join(__dirname, "/bin/data.json"), uid); 
  120.     let status = operate === "confirm" ? "verified" : "canceled"; 
  121.     if (jsonData === null) { 
  122.       jsonData = { 
  123.         uid: uid, 
  124.         status: status, 
  125.         name: "USER", 
  126.     } else { 
  127.       jsonData = JSON.parse(jsonData); 
  128.       jsonData.status = status; 
  129.     setJSONValue(path.join(__dirname, "/bin/data.json"), uid, jsonData); 
  130.     if (status === "verified") { 
  131.       res.writeHead(200, { "Content-Type": "text/html" }); 
  132.       res.end("<h1 style='textAlign:center;'>登录成功!</h1>"); 
  133.     } else { 
  134.       res.writeHead(200, { "Content-Type": "text/html" }); 
  135.       res.end("<h1 style='textAlign:center;'>Canceled!</h1>"); 
  136.   } else { 
  137.     res.writeHead(414, { "Content-Type": "text/html" }); 
  138.     res.end("<h1 style='textAlign:center;'>414 Request-URI Too Large</h1>"); 
  139. // 响应主页不断的AJAX请求 
  140. app.get("/verified", function (req, res) { 
  141.   let uid = url.parse(req.url, true).query.uid; 
  142.   // normal   - 没有任何触发 
  143.   // scanned  - 已扫描 
  144.   // canceled - 已取消 
  145.   // verified - 已验证 
  146.   let dataStatus = { 
  147.     cmd: "normal", 
  148.     user: "", 
  149.   console.log("uid: '" + uid + "' query ..."); 
  150.   if (typeof uid !== "undefined") { 
  151.     let userData = getJSONValue(path.join(__dirname, "/bin/data.json"), uid); 
  152.     // 返回JSON数据用于首页AJAX操作 
  153.     if (userData !== null) { 
  154.       userData = JSON.parse(userData); 
  155.       dataStatus.cmd = userData.status; 
  156.       dataStatus.user = userData.name; 
  157.   res.end(JSON.stringify(dataStatus)); 
  158. server.listen(4000); 
  159. console.log( 
  160.   "Express server listening on port %d in %s mode", 
  161.   server.address().port, 
  162.   app.settings.env 

看到这里,你是不是觉得代码不够全,咋就给了一个主要逻辑代码,别着急,代码满汉全席马上奉上,代码解释可以看注释哦!以下是github网址,如果觉得对自己有用,欢迎star~

  1. https://github.com/maomincoding/qrcodelogin.git 

结语

看到这里了,你可能直接拉取代码,发现项目咋运行不了呢?效果也不跟线上网址那样。是这样的,如果你有线上服务器,可以把它部署到云端。如果没有线上服务器,你可以自己搭建一个本地局域网服务器。一定要保证手机跟电脑网页在一个IP网段上。

效果图如下:

登录网页

登录授权页

【编辑推荐】

【责任编辑:姜华 TEL:(010)68476606】
点赞 0

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK