单点登录 (SSO) 是一种身份验证机制,允许用户登录一次并访问多个连接的应用程序或系统,而无需对每个应用程序或系统进行重新身份验证。 SSO 将用户身份验证集中到单个受信任的系统(通常称为身份提供商或 IdP)中,然后该系统管理凭据并颁发令牌或会话数据以跨其他服务(称为服务提供商或 SP)验证用户的身份。 🎜>
在本指南中,我们将探讨 SSO 的工作原理、其优点和缺点、常见用例以及 API(带有 Express 的 Node.js)、主应用程序 (React) 和外部应用程序中 SSO 实现的示例应用程序(反应)。通过了解 SSO 的原理和实践,组织可以增强其应用程序和系统的用户体验、安全性和运营效率。目录
-
单点登录 (SSO)
-
- SSO 如何工作?
- SSO 的好处
- SSO 的缺点
- SSO 用例
- SSO 实施示例
- 1. API(带有 Express 的 Node.js)
- 2.主要应用程序(React)
- 3.外部应用程序(React)
结论
- GitHub 存储库
单点登录 (SSO) 是一种身份验证机制,允许用户登录一次即可访问多个连接的应用程序或系统,而无需对每个应用程序或系统进行重新身份验证。
SSO 将用户身份验证集中到单个受信任的系统(通常称为身份提供商或 IdP)中,然后该系统管理凭据并颁发令牌或会话数据,以跨其他服务(称为服务提供商或 SP)验证用户身份).
单点登录如何工作?
SSO 通过基于安全令牌的机制(例如 OAuth 2.0、OpenID Connect (OIDC) 或安全断言标记语言 (SAML))进行操作。这是一个简化的流程:
- 用户登录:用户在身份提供商 (IdP) 中输入其凭据。
- 令牌颁发:IdP 验证凭据并颁发身份验证令牌(例如 JWT 或 SAML 断言)。
- 服务访问:令牌被传递给服务提供商,服务提供商对其进行验证并授予访问权限,而无需进一步登录。
-
增强的用户体验:用户只需一次登录即可访问多项服务,减少摩擦并提高可用性。
-
提高安全性:
- 减少密码疲劳,避免密码重复使用等不安全行为。
- 集中式身份验证可实现更强大的密码策略并实施多重身份验证 (MFA)。
-
简化的用户管理:
- 管理员可以更轻松地管理跨连接应用程序的用户访问。
- 从 IdP 撤销对用户的访问权限会禁用他们对所有集成系统的访问权限。
-
时间和成本效率:
- 通过减少与登录相关的帮助台请求,为用户和支持团队节省时间。
- 通过利用现有的身份验证机制减少开发时间和成本。
-
合规与审核:
- 集中式身份验证和访问控制使执行安全策略和跟踪用户活动变得更加容易。
单点登录的缺点
-
单点故障:
- 如果 IdP 不可用或受到威胁,用户将无法访问任何连接的系统。
- 缓解措施:使用冗余 IdP 并确保高可用性。
-
复杂的实现:
- 集成 SSO 需要大量的规划和专业知识,尤其是在具有不同应用程序和协议的环境中。
- 缓解措施:利用 OAuth 2.0 或 SAML 等既定协议以及强大的 SSO 库。
-
安全风险:
- 如果攻击者获得对用户 SSO 凭据的访问权限,他们就有可能访问所有连接的系统。
- 缓解措施:实施强大的 MFA 并监控可疑的登录活动。
-
供应商锁定:
- 组织可能严重依赖特定的 IdP 供应商,这使得迁移充满挑战。
- 缓解措施:选择开放标准并避免专有解决方案。
-
代币管理挑战:
- 过期或被盗的令牌可能会中断访问或造成安全漏洞。
- 缓解措施:实施令牌过期、刷新机制和安全令牌存储。
SSO 用例
-
企业应用:
- 员工只需登录即可访问各种内部工具和服务。
- 简化入职和离职流程。
-
云服务:
- 用户可以在云应用之间无缝切换,无需重复登录。
- 提高生产力和用户体验。
-
客户门户:
- 为不同服务的客户提供统一的登录体验。
- 实现个性化和有针对性的营销。
-
合作伙伴集成:
- 促进对合作伙伴组织之间共享资源的安全访问。
- 简化协作和数据交换。
SSO 实施示例
1. API(Node.js 和 Express)
API 充当身份提供商 (IdP)。它对用户进行身份验证并颁发 JWT 令牌进行访问。
下面是所提供代码的结构化细分,为您的关注者解释了每个部分的目的。这是如何在 API 层实现 SSO 功能的可靠示例。
设置和依赖关系
此设置中使用了以下软件包:
- express:用于处理 HTTP 请求和路由。
- jsonwebtoken:用于生成和验证 JWT。
- cors:用于处理来自不同客户端应用程序的跨源请求。
- @faker-js/faker:用于生成模拟用户和待办事项数据。
- cookie-parser:用于解析请求中发送的cookie。
- dotenv:用于安全地加载环境变量。
配置
- dotenv 用于安全地管理密钥。
- 为开发环境提供了后备秘密。
dotenv.config(); const SECRET_KEY = process.env.SECRET_KEY || "secret";
中间件
- CORS 确保允许来自特定前端来源(主应用程序和外部应用程序)的请求。
- cookieParser 解析客户端发送的 cookie。
- express.json 允许解析 JSON 请求主体。
app.use( cors({ origin: ["http://localhost:5173", "http://localhost:5174"], credentials: true, }) ); app.use(express.json()); app.use(cookieParser());
用户身份验证和令牌生成
模拟数据模拟用户及其关联的待办事项。
用户拥有角色(管理员或用户)和基本个人资料信息。
待办事项链接到用户 ID 以进行个性化访问。
- /login:根据电子邮件和密码对用户进行身份验证。
用户成功登录后会收到包含 JWT 的 cookie (sso_token)。
该令牌是安全的、仅限 HTTP 且有时间限制以防止篡改。
app.post("/login", (req, res) => { const { email, password } = req.body; const user = users.find( (user) => user.email === email && user.password === password ); if (user) { const token = jwt.sign({ user }, SECRET_KEY, { expiresIn: "1h" }); res.cookie("sso_token", token, { httpOnly: true, secure: process.env.NODE_ENV === "production", maxAge: 3600000, sameSite: "strict", }); res.json({ message: "Login successful" }); } else { res.status(400).json({ error: "Invalid credentials" }); } });
- /verify:通过解码令牌来验证用户的身份。无效令牌会导致未经授权的响应。
app.get("/verify", (req, res) => { const token = req.cookies.sso_token; if (!token) { return res.status(401).json({ authenticated: false }); } try { const decoded = jwt.verify(token, SECRET_KEY); res.json({ authenticated: true, user: decoded }); } catch { res.status(401).json({ authenticated: false, error: "Invalid token" }); } });
- /logout:清除包含 JWT 令牌的 cookie。
确保用户可以通过清除令牌来安全注销。
dotenv.config(); const SECRET_KEY = process.env.SECRET_KEY || "secret";
- /todos:检索与经过身份验证的用户关联的待办事项。
app.use( cors({ origin: ["http://localhost:5173", "http://localhost:5174"], credentials: true, }) ); app.use(express.json()); app.use(cookieParser());
- /todos:为经过身份验证的用户添加新的待办事项。
app.post("/login", (req, res) => { const { email, password } = req.body; const user = users.find( (user) => user.email === email && user.password === password ); if (user) { const token = jwt.sign({ user }, SECRET_KEY, { expiresIn: "1h" }); res.cookie("sso_token", token, { httpOnly: true, secure: process.env.NODE_ENV === "production", maxAge: 3600000, sameSite: "strict", }); res.json({ message: "Login successful" }); } else { res.status(400).json({ error: "Invalid credentials" }); } });
- /todos/:id:根据提供的 ID 更新待办事项。
app.get("/verify", (req, res) => { const token = req.cookies.sso_token; if (!token) { return res.status(401).json({ authenticated: false }); } try { const decoded = jwt.verify(token, SECRET_KEY); res.json({ authenticated: true, user: decoded }); } catch { res.status(401).json({ authenticated: false, error: "Invalid token" }); } });
- /todos/:id:根据提供的 ID 删除待办事项。
app.post("/logout", (req, res) => { res.clearCookie("sso_token"); res.json({ message: "Logout successful" }); });
2. 主要应用程序(React)
主应用程序充当服务提供商 (SP),使用 API 并管理用户交互。
下面是所提供代码的结构化细分,为您的关注者解释了每个部分的目的。这是如何在主应用程序层中实现 SSO 功能的可靠示例。
- 应用程序组件
App 组件管理用户身份验证并根据登录状态进行重定向。
app.get("/todos/:userId", (req, res) => { const ssoToken = req.cookies.sso_token; const user = getUser(ssoToken); if (!user) { return res.status(401).json({ error: "Unauthorized" }); } const userTodos = todos.filter((todo) => todo.userId === user.id); res.json(userTodos); });
- 登录组件
登录组件处理用户登录并在身份验证成功后重定向到 Todos 页面。
app.post("/todos", (req, res) => { const ssoToken = req.cookies.sso_token; const user = getUser(ssoToken); if (!user) { return res.status(401).json({ error: "Unauthorized" }); } const { title, description } = req.body; const newTodo = { id: faker.string.uuid(), userId: user.id, title, description, }; todos.push(newTodo); res.status(201).json({ message: "Todo added successfully", data: newTodo }); });
- 待办事项组件
Todos 组件显示用户特定的待办事项并允许添加和删除待办事项。
// Update a todo app.put("/todos/:id", (req, res) => { const ssotoken = req.cookies.sso_token; const user = getUser(ssotoken); if (!user) { return res.status(401).json({ message: "Unauthorized" }); } const { id } = req.params; const { title, description } = req.body; const index = todos.findIndex((todo) => todo.id === id); if (index !== -1) { todos[index] = { ...todos[index], title, description, }; res.json({ message: "Todo updated successfully", data: todos[index], }); } else { res.status(404).json({ message: "Todo not found" }); } });
3. 外部应用程序(React)
外部应用程序充当另一个服务提供商 (SP),使用 API 并管理用户交互。
下面是所提供代码的结构化细分,为您的关注者解释了每个部分的目的。这是如何在外部应用程序层实现 SSO 功能的可靠示例。
- 应用程序组件
App 组件管理用户身份验证并根据登录状态进行重定向。
// Delete a todo app.delete("/todos/:id", (req, res) => { const ssoToken = req.cookies.sso_token; const user = getUser(ssoToken); if (!user) { return res.status(401).json({ message: "Unauthorized" }); } const { id } = req.params; const index = todos.findIndex((todo) => todo.id === id); if (index !== -1) { todos = todos.filter((todo) => todo.id !== id); res.json({ message: "Todo deleted successfully" }); } else { res.status(404).json({ message: "Todo not found" }); } });
- 待办事项组件
Todos 组件显示用户特定的待办事项。
import { useState, useEffect } from "react"; import { Navigate, Route, Routes, useNavigate, useSearchParams, } from "react-router-dom"; import Todos from "./components/Todos"; import Login from "./components/Login"; import { toast } from "react-toastify"; import api from "./api"; function App() { const [isLoggedIn, setIsLoggedIn] = useState(false); const [searchParams] = useSearchParams(); const navigate = useNavigate(); useEffect(() => { const verifyLogin = async () => { const returnUrl = searchParams.get("returnUrl"); try { const response = await api.get("/verify", { withCredentials: true, }); if (response.data.authenticated) { setIsLoggedIn(true); toast.success("You are logged in."); navigate("/todos"); } else { setIsLoggedIn(false); if (!returnUrl) { toast.error("You are not logged in."); } } } catch (error) { setIsLoggedIn(false); console.error("Verification failed:", error); } }; verifyLogin(); const handleVisibilityChange = () => { if (document.visibilityState === "visible") { verifyLogin(); } }; document.addEventListener("visibilitychange", handleVisibilityChange); return () => { document.removeEventListener("visibilitychange", handleVisibilityChange); }; }, [navigate, searchParams]); return ( <div classname="container p-4 mx-auto"> <routes> <route path="/" element="{<Login"></route>} /> <route path="/todos" element="{isLoggedIn"></route> : <navigate to='{"/"}'></navigate>} /> </routes> </div> ); } export default App;
结论
单点登录 (SSO) 简化了跨多个应用程序的用户身份验证和访问管理,从而增强了用户体验、安全性和运营效率。通过集中身份验证并利用基于安全令牌的机制,组织可以简化用户访问、降低与密码相关的风险并提高合规性和审核能力。
虽然 SSO 提供了众多好处,但它也带来了挑战,例如单点故障、复杂的实施要求、安全风险和潜在的供应商锁定。组织必须仔细规划和实施 SSO 解决方案,以减轻这些风险并最大限度地发挥集中式身份验证的优势。
通过遵循最佳实践、利用既定协议并选择开放标准,组织可以成功实施 SSO,以增强其应用程序和系统的用户体验、安全性和运营效率。
以上是单点登录 (SSO):React 和 ExpressJS 综合指南的详细内容。更多信息请关注PHP中文网其他相关文章!

JavaScript在Web开发中的主要用途包括客户端交互、表单验证和异步通信。1)通过DOM操作实现动态内容更新和用户交互;2)在用户提交数据前进行客户端验证,提高用户体验;3)通过AJAX技术实现与服务器的无刷新通信。

理解JavaScript引擎内部工作原理对开发者重要,因为它能帮助编写更高效的代码并理解性能瓶颈和优化策略。1)引擎的工作流程包括解析、编译和执行三个阶段;2)执行过程中,引擎会进行动态优化,如内联缓存和隐藏类;3)最佳实践包括避免全局变量、优化循环、使用const和let,以及避免过度使用闭包。

Python更适合初学者,学习曲线平缓,语法简洁;JavaScript适合前端开发,学习曲线较陡,语法灵活。1.Python语法直观,适用于数据科学和后端开发。2.JavaScript灵活,广泛用于前端和服务器端编程。

Python和JavaScript在社区、库和资源方面的对比各有优劣。1)Python社区友好,适合初学者,但前端开发资源不如JavaScript丰富。2)Python在数据科学和机器学习库方面强大,JavaScript则在前端开发库和框架上更胜一筹。3)两者的学习资源都丰富,但Python适合从官方文档开始,JavaScript则以MDNWebDocs为佳。选择应基于项目需求和个人兴趣。

从C/C 转向JavaScript需要适应动态类型、垃圾回收和异步编程等特点。1)C/C 是静态类型语言,需手动管理内存,而JavaScript是动态类型,垃圾回收自动处理。2)C/C 需编译成机器码,JavaScript则为解释型语言。3)JavaScript引入闭包、原型链和Promise等概念,增强了灵活性和异步编程能力。

不同JavaScript引擎在解析和执行JavaScript代码时,效果会有所不同,因为每个引擎的实现原理和优化策略各有差异。1.词法分析:将源码转换为词法单元。2.语法分析:生成抽象语法树。3.优化和编译:通过JIT编译器生成机器码。4.执行:运行机器码。V8引擎通过即时编译和隐藏类优化,SpiderMonkey使用类型推断系统,导致在相同代码上的性能表现不同。

JavaScript在现实世界中的应用包括服务器端编程、移动应用开发和物联网控制:1.通过Node.js实现服务器端编程,适用于高并发请求处理。2.通过ReactNative进行移动应用开发,支持跨平台部署。3.通过Johnny-Five库用于物联网设备控制,适用于硬件交互。

我使用您的日常技术工具构建了功能性的多租户SaaS应用程序(一个Edtech应用程序),您可以做同样的事情。 首先,什么是多租户SaaS应用程序? 多租户SaaS应用程序可让您从唱歌中为多个客户提供服务


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

MinGW - 适用于 Windows 的极简 GNU
这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

Dreamweaver CS6
视觉化网页开发工具

WebStorm Mac版
好用的JavaScript开发工具

ZendStudio 13.5.1 Mac
功能强大的PHP集成开发环境

记事本++7.3.1
好用且免费的代码编辑器