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

Jacquelyn38
• 阅读 1523

前言

首先,我们看一下微信开放文档中的一张图:手写一个仿微信登录的nodejs程序上面的一幅图中清楚地介绍了微信登录整个过程,下面对图上所示进行总结:

一、二维码的获得

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

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

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

二、微信客户端授权登录

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

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

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

三、网页后台请求数据

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

  2. 登录网页后台根据code参数,再加上AppIDAppSecret请求微信开发平台换取access_token

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

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

实现

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

`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 style='textAlign:center;'>登录成功!</h1>");  
    } else {  
      res.writeHead(200, { "Content-Type": "text/html" });  
      res.end("<h1 style='textAlign:center;'>Canceled!</h1>");  
    }  
  } else {  
    res.writeHead(414, { "Content-Type": "text/html" });  
    res.end("<h1 style='textAlign:center;'>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  
);  
`

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

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

结语

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

效果图如下:

  1. 登录网页

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

  1. 登录授权页

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

  • 欢迎关注我的公众号 前端历劫之路

  • 回复关键词 电子书 ,即可获取12本前端热门电子书

  • 回复关键词 红宝书第4版 ,即可获取最新《JavaScript高级程序设计》(第四版)电子书

  • 关注公众号后,点击下方菜单即可加我微信,我拉拢了很多IT大佬,创建了一个技术交流、文章分享群,期待你的加入手写一个仿微信登录的nodejs程序

- END -

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

本文转转自微信公众号前端历劫之路原创https://mp.weixin.qq.com/s/w4cBaLQoRAAUlOHRpcmf_A,如有侵权,请联系删除。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
梦
3年前
微信小程序new Date()转换时间异常问题
微信小程序苹果手机页面上显示时间异常,安卓机正常问题image(https://imghelloworld.osscnbeijing.aliyuncs.com/imgs/b691e1230e2f15efbd81fe11ef734d4f.png)错误代码vardate'2021030617:00:00'vardateT
Easter79 Easter79
2年前
thinkcmf+jsapi 实现微信支付
首先从小程序端接收订单号、金额等参数,然后后台进行统一下单,把微信支付的订单号返回,在把订单号发送给前台,前台拉起支付,返回参数后更改支付状态。。。回调publicfunctionnotify(){$wechatDb::name('wechat')where('status',1)find();
Wesley13 Wesley13
2年前
Oracle ADG究竟是否收费?
!(https://oscimg.oschina.net/oscnet/faaf5c218b3045fe9a38ffa00c48a996.png)前两天微信群中,有位朋友问了,OracleDatabaseStandardEdition11gR2标准版支持activedataguard么?可能平时
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
2年前
C#开发——网站应用微信登录开发
1\.在微信开放平台注册开发者账号,并有一个审核已通过的网站应用,并获得相对应的AppID和AppSecret,申请通过登陆后,方可开始接入流程。2.微信OAuth2.0授权登录目前支持authorization\_code模式,适用于拥有server端的应用授权。该模式整体流程为:1.第三方发起微信授权登录请求,微信用户允许授权第三方应
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这