Nodejs 第六十四章(SSO单点登录)

Nodejs 第六十四章(SSO单点登录)单点登录 单点登录 Single Sign On 简称 SSO 是一种身份认证和访问控制的机制 允许用户使用一组凭据 如用户名和密码 登录到多个应用程序或系统 而无需为每个应用程序单独提供凭据 SSO 的主要优点包括 用户友好性

大家好,我是讯享网,很高兴认识大家。

单点登录

单点登录(Single Sign-On,简称SSO)是一种身份认证和访问控制的机制,允许用户使用一组凭据(如用户名和密码)登录到多个应用程序或系统,而无需为每个应用程序单独提供凭据

SSO的主要优点包括:

  1. 用户友好性:用户只需登录一次,即可访问多个应用程序,提供了更好的用户体验和便利性。
  2. 提高安全性:通过集中的身份验证,可以减少密码泄露和密码管理问题。此外,SSO还可以与其他身份验证机制(如多因素身份验证)结合使用,提供更强的安全性。
  3. 简化管理:SSO可以减少管理员的工作量,因为他们不需要为每个应用程序单独管理用户凭据和权限。

举例说明

小满科技,小满教育,都是小满旗下的公司,那么我需要给每套系统做一套登录注册,人员管理吗,那太费劲了,于是使用SSO单点登录,只需要在任意一个应用登录过,其他应用便是免登录的一个效果,如果过期了,在重新登录

但是每个应用是不同的,登录用的是一套,这时候可以模仿一下微信小程序的生成一个AppId作为应用ID,并且还可以创建一个secret,因为每个应用的权限可以不一样,所以最后生成的token也不一样,还需要一个url,登录之后重定向到该应用的地址,正规做法需要有一个后台管理系统用来控制这些,注册应用,删除应用,这里节约时间就写死了。

image.png
讯享网

代码编写

  1. 安装的依赖
  • express 启动服务编写接口
  • express-session 操作cookie
  • jsonwebtoken 生成token
  • cors 跨域
  1. 目录结构
  • vue A项目 用vite创建一个就好 npm init vite
  • react B项目 用vite创建一个就好 npm init vite
  • server/index.js nodejs端
  • sso.html 登录页面

server/index.js

const appToMapUrl = { 
    //A应用id 'Rs6s2aHi': { 
    url: "http://localhost:5173", //对应的应用地址 secretKey: '%Y&*VGHJKLsjkas', //对应的secretKey token:"" //token }, //B应用id '9LQ8Y3mB': { 
    url: "http://localhost:5174", //对应的应用地址 secretKey: '%Y&*FRTYGUHJIOKL', //对应的secretKey token:"" //token }, } 

讯享网

完整版代码

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 = { 
    'Rs6s2aHi': { 
    url: "http://localhost:5173", name:'vue', secretKey: '%Y&*VGHJKLsjkas', token: "" }, '9LQ8Y3mB': { 
    url: "http://localhost:5174", secretKey: '%Y&*FRTYGUHJIOKL', name:'react', token: "" }, } const app = express() app.use(cors()) app.use(express.json()) app.use(session({ 
    secret: "$%^&*()_+DFGHJKL", cookie: { 
    maxAge: 1000 * 60 * 60 * 24 * 7, //过期时间 } })) const genToken = (appId) => { 
    return jwt.sign({ 
    appId }, appToMapUrl[appId].secretKey) } app.get('/login', (req, res) => { 
    //注意看逻辑 如果登陆过 就走if 没有登录过就走下面的 if (req.session.username) { 
    //登录过 const appId = req.query.appId const url = appToMapUrl[appId].url let token; //登录过如果存过token就直接取 没有存过就生成一个 因为可能有多个引用A登录过读取Token B没有登录过生成Token 存入映射表 if (appToMapUrl[appId].token) { 
    token = appToMapUrl[appId].token } else { 
    token = genToken(appId) appToMapUrl[appId].token = token } res.redirect(url + '?token=' + token) return } //没有登录 返回一个登录页面html const html = fs.readFileSync(`../sso.html`, 'utf-8') //返回登录页面 res.send(html) }) //提供protectd get接口 重定向到目标地址 app.get('/protectd', (req, res) => { 
    const { 
    appId,username,password } = req.query //获取应用标识 const url = appToMapUrl[appId].url //读取要跳转的地址 const token = genToken(appId) //生成token req.session.username = username //存储用户名称 表示这个账号已经登录过了 下次无需登录 appToMapUrl[appId].token = token //根据应用存入对应的token res.redirect(url + '?token=' + token) //定向到目标页面 }) //启动3000端口 app.listen(3000, () => { 
    console.log('http://localhost:3000') }) 

sso.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> <!--这里会调用protectd接口 并且会传入 账号 密码 和 appId appId会从地址栏读取--> <form action="/protectd" method="get"> <label for="username"> 账号:<input name="username" id="username" type="text"> </label> <label for="password">密码:<input name="password" id="password" type="password"></label> <label for="appId"><input name="appId" value="" id="appId" type="hidden"></label> <button type="submit" id="button">登录</button> </form> <script> //读取AppId const appId = location.search.split('=')[1] document.getElementById('appId').value = appId </script> </body> </html> 

A 应用这里用Vue展示 App.vue

讯享网<template> <h1>vue3</h1> </template> <script setup lang='ts'> //如果有token代表登录过了 如果没有跳转到 登录页面也就是SSO 那个页面,并且地址栏携带AppID const token = location.search.split('=')[1] if (!token) { 
      fetch('http://localhost:3000/login?appId=Rs6s2aHi').then(res => { 
      location.href = res.url }) } </script> <style></style> 

B应用使用React演示 App.tsx

import { useState } from 'react' function App() { const [count, setCount] = useState(0) //逻辑其实一样的只是区分了不用应用的AppId const token = location.search.split('=')[1] if (!token) { fetch('http://localhost:3000/login?appId=9LQ8Y3mB').then(res => { location.href = res.url }) } return ( <> <h1>react</h1> </> ) } export default App 
小讯
上一篇 2025-03-22 18:53
下一篇 2025-03-05 10:24

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/64600.html