Node.js 扫码登录(SCL)
用户通过手机扫描二维码完成 PC 端登录,无需手动输入用户名密码。
优势
| 优势 | 说明 |
|---|---|
| 方便快捷 | 扫码即登录 |
| 安全性高 | 加密传输,降低密码泄露风险 |
| 防键盘记录 | 无需键盘输入敏感信息 |
| 适用广泛 | 统一登录方式,跨平台集成 |
实现流程
PC端 服务端 手机端
│ │ │
│── GET /qrcode ──────────→│ │
│←── 返回二维码(含临时token) │ │
│ │ │
│── 轮询 /check ───────────→│ │
│←── { status: 'pending' } │ │
│ │ │
│ │←── 手机扫码, POST /confirm│
│ │ (临时token + 用户token)│
│ │── 验证通过, 设置状态为OK │
│ │←── { success: true } │
│ │ │
│── 轮询 /check ───────────→│ │
│←── { status: 'ok', token }│ │
│ PC端拿到JWT完成登录 │ │依赖
bash
npm install express jsonwebtoken qrcode核心代码
生成二维码(PC端调用)
js
import QRCode from 'qrcode'
import { v4 as uuid } from 'uuid'
const qrStore = {} // 临时存储
app.get('/qrcode', (req, res) => {
const qrcodeId = uuid()
qrStore[qrcodeId] = { status: 'pending' } // 初始未扫码
const qrDataUrl = await QRCode.toDataURL(`http://localhost:3000/confirm?qrcodeId=${qrcodeId}`)
res.json({ qrcodeId, qrDataUrl })
})PC端轮询检查
js
app.get('/check', (req, res) => {
const { qrcodeId } = req.query
const qrData = qrStore[qrcodeId]
if (qrData?.status === 'ok') {
const token = jwt.sign({ userId: qrData.userId }, secret, { expiresIn: '7d' })
res.json({ status: 'ok', token })
delete qrStore[qrcodeId]
} else {
res.json({ status: 'pending' })
}
})手机端确认
js
app.post('/confirm', (req, res) => {
const { qrcodeId } = req.body
// 从请求头中获取已登录用户的 token
const userToken = req.headers.authorization
const decoded = jwt.verify(userToken, secret)
qrStore[qrcodeId] = { status: 'ok', userId: decoded.userId }
res.json({ success: true })
})关键点
- 二维码有效期要短(1-2 分钟),过期需刷新
- 状态可用 Redis 存储(带 TTL)
- 手机端扫码后需要用户手动确认(防误操作)