Nodejs 第六十六章(SCL扫码登录)

扫码登录

SCL (Scan Code Login) 是一种扫码登录的技术,它允许用户通过扫描二维码来进行登录操作。这种登录方式在许多应用和网站中得到广泛应用,因为它简单、方便且安全。

SCL 扫码登录的优点包括:

  1. 方便快捷:用户只需打开扫码应用程序并扫描二维码即可完成登录,无需手动输入用户名和密码。
  2. 安全性高:扫码登录采用了加密技术,用户的登录信息在传输过程中得到保护,降低了密码被盗取或泄露的风险。
  3. 避免键盘记录:由于用户无需在登录过程中输入敏感信息,如用户名和密码,因此不会受到键盘记录软件的威胁。
  4. 适用性广泛:SCL 扫码登录可以与不同的应用和网站集成,提供统一的登录方式,使用户无需记住多个账户的用户名和密码。

实现流程

安装的依赖

  1. express 提供接口服务
  2. jsonwebtoken 生成token
  3. qrcode 生成二维码

流程图

大体逻辑

js 复制代码
  const status = {
    0: '未授权',
    1: '已授权',
    2: '超时'
}
  1. 需要一个页面调用接口获取qrcode也就是二维码去展示,然后顺便展示一下状态,默认0 未授权
  2. 在这个页面轮询接口检查状态是否是已授权,如果是已授权或者超时就停止轮询。
  3. 扫码之后会打开授权页面,在授权页面点击确认按钮进行授权分配token

代码实现

目录结构

public

  1. mandate.html 授权页面
  2. qrcode.html 二维码页面

index.js nodejs逻辑代码

index.js

js 复制代码
import express from 'express'
import qrcode from 'qrcode'
import jwt from 'jsonwebtoken'

let user = {

}
let userId = 1 //模拟一个用户
const app = express()
app.use(express.json())
app.use('/static', express.static('public')) //初始化静态目录
//初始化数据结构 记录用户和创建二维码的时间
//并且生成二维码的时候使用的是授权的那个页面并且把用户id带过去
app.get('/qrcode', async (req, res) => {
    user[userId] = {
        token: null,
        time: Date.now()
    }
    const code = await qrcode.toDataURL(`http://192.168.120.145:3000/static/mandate.html?userId=${userId}`)
    res.json({
        code,
        userId
    })
})
//授权确认接口 陈功授权之后生成token
app.post('/login/:userId', (req, res) => {
    const token = jwt.sign(req.params.userId, 'secret')
    user[req.params.userId].token = token
    user[req.params.userId].time = Date.now()
    res.json({
        token
    })
})
//检查接口 这个接口要被轮询调用检查状态,0未授权 1已授权 2超时
app.get('/check/:userId', (req, res) => {
    //判断超时时间
    if (Date.now() - user[userId].time > 1000 * 60 * 1) {
        return res.json({
            status: 2
        })
    }
    //如果有token那就是验证成功
    else if (user[1].token) {
        return res.json({
            status: 1
        })
    } else {
        return res.json({
            status: 0
        })
    }
})

app.listen(3000, () => {
    console.log('http://localhost:3000')
})

qrcode.html

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <img id="qrcode" src="" alt="">
    <div id="status-div"></div>
    <script>
        const status = {
            0: '未授权',
            1: '已授权',
            2: '超时'
        }
        const qrcode = document.getElementById('qrcode')
        const statusDiv = document.getElementById('status-div')
        let userId = null
        statusDiv.innerText = status[0]
        fetch('/qrcode').then(res => res.json()).then(res => {
            qrcode.src = res.code //获取二维码
            userId = res.userId //获取用户id
            let timer = setInterval(() => {
               //轮询调用检查接口
                fetch(`/check/${userId}`).then(res => res.json()).then(res => {
                    statusDiv.innerText = status[res.status]
                    //如果返回的状态是 超时 或者是已授权 就停止轮训
                    if (res.status != 0) {
                        clearInterval(timer)
                    }
                })
            }, 1000)
        })

    </script>
</body>

</html>

mandate.html

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div> <button id="btn" style="width: 100%;height: 50px;">同意授权</button></div>
    <div> <button style="width: 100%;height: 50px;margin-top: 20px;">拒绝授权</button></div>
    <script>
        const btn = document.getElementById('btn')
        let userId = location.search.slice(1).split('=')[1]
        btn.onclick = () => {
            //点击授权按钮
            fetch(`/login/${userId}`, {
                method: 'POST',
            }).then(res => res.json()).then(res => {
                alert(`授权成功`)
            }).catch(err => {
                alert(err)
            })
        }
    </script>
</body>

</html>

效果预览

相关推荐
zhanlang021718 分钟前
HTML 零基础入门到企业实战全套教程【连载 5.3】audio、video 音频视频标签|兼容格式、自动播放踩坑、企业规范
前端·html
w3296362711 小时前
飞书接单到月度结算:我用一个 DSH 插件跑通鞋类采购 WMS,附 22 项验收
pdf·node.js·飞书·后端开发·ai agent
qq_406981031 小时前
c++ lamda(三)Lambda表达式
java·前端·c++
zhanlang02171 小时前
HTML 零基础入门到企业实战【第五章 5.4】内嵌网页 iframe 标签:嵌入网页、视频、地图实战
前端·html·音视频
2分钟速写快排9 小时前
孔乙己的茴字有多少种写法?|AI 对话实时通信的三种实现
前端·javascript·github
Penge66611 小时前
JavaScript:BOM 详解
前端
Penge66611 小时前
Vite vs Webpack:前端构建工具原理与实战
前端
Penge66611 小时前
前端包管理工具:npm、Yarn、pnpm 快速入门
前端
Penge66612 小时前
Sass 了解
前端
Penge66612 小时前
Webpack 打包从 0 到 1 实战笔记
前端