Node.js单点登录SSO详解:Session、JWT、CORS让登录更简单(二)

简介: Node.js单点登录SSO详解:Session、JWT、CORS让登录更简单(一)

Node.js单点登录SSO详解:Session、JWT、CORS让登录更简单(一):https://developer.aliyun.com/article/1628445


三、SSO实现方案

1、安装依赖

启动服务:express

操作cookie:express-session

生成token:jsonwebtoken

解决跨域:cors

npm install express
npm install express-session
npm install jsonwebtoken
npm install cors
2、结构

vueA项目:使用vite创建项目

vueB项目:使用vite创建项目

nodejs端:server/index.js

登录页面:login.html

3、实现原理
  • 用户首次访问系统A或B时,需要进行登录。
  • 系统统A或B带着appId信息重定向登录页面。
  • 认证系统验证用户登录信息。
  • 验证通过后,设置session值,用户返回一个token。
  • 认证系统带着token重定向给系统A或B,得知用户是已登录状态。
  • 系统A或B正常进入系统。
  • 用户再访问另一个系统时。
  • 通过session值,得知用户是已登录状态。
  • 认证系统带着token重定向给系统。
  • 系统正常进入系统。


四、示例代码

1、nodejs端 server/index.js
import express from "express"
import session from 'express-session'
import fs from "node:fs"
import cors from "cors"
import jwt from 'jsonwebtoken'


// 应用列表
const appToMapUrl = {
    'fd8xIoDC': {
        url: 'http://localhost:5173',
        name: 'appA',
        secret: '123456',
        token: ''
    },
    'DDkq0YYh': {
        url: 'http://localhost:5174',
        name: 'appB',
        secret: '789102',
        token: ''
    }
}


// 创建服务器
const app = express()


// 解析post请求体
app.use(express.json())

// 跨域
app.use(cors())

// 创建session配置项,注册为express-session中间件
app.use(session({
    secret: '123456',//加密字符串。 使用该字符串来加密session数据,自定义
    resave: false,//强制保存session即使它并没有变化
    saveUninitialized: true,//强制将未初始化的session存储。当新建了一个session且未设定属性或值时,它就处于未初始化状态。
    cookie: {
        maxAge: 30 * 60 * 1000
    }
}))


//获取token
const getToken = (appId) => {
    const appInfo = appToMapUrl[appId]
    if (!appInfo) {
        return null;
    }
    // 生成token
    const token = jwt.sign({
        id: appId,
        name: appInfo.name,
        secret: appInfo.secret
    }, '123456', {
        expiresIn: 60 * 60
    })
    return token;
}


//是否登录
app.get('/login', (req, res) => {
    const {appId} = req.query
    if (!appId) {
        return res.send('请输入appId')
    }
    // 判断是否登录
    if (req.session.userName) {
        let token
        if (appToMapUrl[appId].token) {
            // 获取token
            token = appToMapUrl[appId].token
        } else {
            // 生成token
            token = getToken(appId)
            // 存入appToMapUrl
            appToMapUrl[appId].token = token
        }
        // 跳转
        res.redirect(`${appToMapUrl[appId].url}?token=${token}`)
        return;
    } else {
        // 读取登录页面
        const html = fs.readFileSync('./login.html', 'utf-8')
        res.send(html)
    }
})

// 解析表单数据
app.use(express.urlencoded({ extended: true }));

// 登录
app.post('/protected', (req, res) => {
    const {username,password,appId} = req.body
    if (username === 'admin' && password === '123456') {
        const token = getToken(appId);
        // 存入appToMapUrl
        appToMapUrl[appId].token = token;
        //存入session,证明已经登录
        req.session.userName = username;
        res.redirect(`${appToMapUrl[appId].url}?token=${token}`)
    } else {
        res.send('用户名或密码错误')
    }
})


// 监听端口
app.listen(3000, () => {
    console.log('http://localhost:3000')
})
2、vueA项目app.vue
<script setup lang="ts">
const token = location.search.split('token=')[1]
if (!token) {
  fetch('http://localhost:3000/login?appId=fd8xIoDC').then(res => {
    location.href = res.url
  })
} else {
  localStorage.setItem('token', token)
}
</script>

<template>
  <div>这里是appA</div>

</template>

<style scoped>
</style>
3、vueB项目app.vue
<script setup>
const token = location.search.split('token=')[1]
if (!token) {
  fetch('http://localhost:3000/login?appId=DDkq0YYh').then(res => {
    location.href = res.url
  })
} else {
  localStorage.setItem('token', token)
}
</script>

<template>
  <div>这里是appB</div>
</template>

<style scoped>
</style>
4、登录页面login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>登录</title>
</head>
<body>
    <div>
        <h1>登录页面</h1>
        <form action="/protected" method="post">
            <input type="text" name="username">
            <input type="password" name="password">
            <input type="hidden" name="appId">
            <input type="submit" value="登录">
        </form>
    </div>
    <script>
        const appId = location.search.split('?')[1].split('=')[1]
        document.querySelector('input[name="appId"]').value = appId
    </script>
</body>
</html>


目录
相关文章
|
前端开发 JavaScript 安全
HTML+CSS+JS密码灯登录表单
通过结合使用HTML、CSS和JavaScript,我们创建了一个带有密码强度指示器的登录表单。这不仅提高了用户体验,还帮助用户创建更安全的密码。希望本文的详细介绍和代码示例能帮助您在实际项目中实现类似功能,提升网站的安全性和用户友好性。
489 3
|
存储 JSON JavaScript
Node.js单点登录SSO详解:Session、JWT、CORS让登录更简单(一)
Node.js单点登录SSO详解:Session、JWT、CORS让登录更简单(一)
804 0
|
JavaScript Unix Linux
nvm与node.js的安装指南
通过以上步骤,你可以在各种操作系统上成功安装NVM和Node.js,从而在不同的项目中灵活切换Node.js版本。这种灵活性对于管理不同项目的环境依赖而言是非常重要的。
3997 11
|
存储 JavaScript 搜索推荐
Node框架的安装和配置方法
安装 Node 框架是进行 Node 开发的第一步,通过正确的安装和配置,可以为后续的开发工作提供良好的基础。在安装过程中,需要仔细阅读相关文档和提示,遇到问题及时解决,以确保安装顺利完成。
1338 155
|
弹性计算 JavaScript 前端开发
一键安装!阿里云新功能部署Nodejs环境到ECS竟然如此简单!
Node.js 是一种高效的 JavaScript 运行环境,基于 Chrome V8 引擎,支持在服务器端运行 JavaScript 代码。本文介绍如何在阿里云上一键部署 Node.js 环境,无需繁琐配置,轻松上手。前提条件包括 ECS 实例运行中且操作系统为 CentOS、Ubuntu 等。功能特点为一键安装和稳定性好,支持常用 LTS 版本。安装步骤简单:登录阿里云控制台,选择扩展程序管理页面,安装 Node.js 扩展,选择实例和版本,等待创建完成并验证安装成功。通过阿里云的公共扩展,初学者和经验丰富的开发者都能快速进入开发状态,开启高效开发之旅。
|
资源调度 JavaScript 前端开发
前端开发必备!Node.js 18.x LTS保姆级安装教程(附国内镜像源配置)
本文详细介绍了Node.js的安装与配置流程,涵盖环境准备、版本选择(推荐LTS版v18.x)、安装步骤(路径设置、组件选择)、环境验证(命令测试、镜像加速)及常见问题解决方法。同时推荐开发工具链,如VS Code、Yarn等,并提供常用全局包安装指南,帮助开发者快速搭建高效稳定的JavaScript开发环境。内容基于官方正版软件,确保合规性与安全性。
16587 23
|
弹性计算 JavaScript 前端开发
一键安装!阿里云新功能部署Nodejs环境到ECS竟然如此简单!
一键安装!阿里云新功能部署Nodejs环境到ECS竟然如此简单!
1010 10
一键安装!阿里云新功能部署Nodejs环境到ECS竟然如此简单!
|
JavaScript 前端开发 数据可视化
【01】Cocos游戏开发引擎从0开发一款游戏-cocos环境搭建以及配置-Cocos Creator软件系统下载安装-node环境-优雅草卓伊凡
【01】Cocos游戏开发引擎从0开发一款游戏-cocos环境搭建以及配置-Cocos Creator软件系统下载安装-node环境-优雅草卓伊凡
1204 2
【01】Cocos游戏开发引擎从0开发一款游戏-cocos环境搭建以及配置-Cocos Creator软件系统下载安装-node环境-优雅草卓伊凡
|
JavaScript
nodejs安装之npm ERR! code CERT_HAS_EXPIREDnpm ERR! errno CERT_HAS_EXPIRED reason: certificate has expired-证书错误通用问题解决方案-优雅草央千澈
nodejs安装之npm ERR! code CERT_HAS_EXPIREDnpm ERR! errno CERT_HAS_EXPIRED reason: certificate has expired-证书错误通用问题解决方案-优雅草央千澈
4015 27