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>

效果预览

相关推荐
前端李易安2 小时前
Web常见的攻击方式及防御方法
前端
PythonFun2 小时前
Python技巧:如何避免数据输入类型错误
前端·python
hakesashou2 小时前
python交互式命令时如何清除
java·前端·python
天涯学馆2 小时前
Next.js与NextAuth:身份验证实践
前端·javascript·next.js
HEX9CF2 小时前
【CTF Web】Pikachu xss之href输出 Writeup(GET请求+反射型XSS+javascript:伪协议绕过)
开发语言·前端·javascript·安全·网络安全·ecmascript·xss
ConardLi2 小时前
Chrome:新的滚动捕捉事件助你实现更丝滑的动画效果!
前端·javascript·浏览器
ConardLi3 小时前
安全赋值运算符,新的 JavaScript 提案让你告别 trycatch !
前端·javascript
凌云行者3 小时前
使用rust写一个Web服务器——单线程版本
服务器·前端·rust
华农第一蒟蒻3 小时前
Java中JWT(JSON Web Token)的运用
java·前端·spring boot·json·token
积水成江3 小时前
关于Generator,async 和 await的介绍
前端·javascript·vue.js