单点登录 (SSO) 是一种身份验证机制,允许用户登录一次并访问多个连接的应用程序或系统,而无需对每个应用程序或系统进行重新身份验证。 SSO 将用户身份验证集中到单个受信任的系统(通常称为身份提供商或 IdP)中,然后该系统管理凭据并颁发令牌或会话数据以跨其他服务(称为服务提供商或 SP)验证用户的身份。 🎜>
在本指南中,我们将探讨 SSO 的工作原理、其优点和缺点、常见用例以及 API(带有 Express 的 Node.js)、主应用程序 (React) 和外部应用程序中 SSO 实现的示例应用程序(反应)。通过了解 SSO 的原理和实践,组织可以增强其应用程序和系统的用户体验、安全性和运营效率。目录
单点登录 (SSO)
SSO 将用户身份验证集中到单个受信任的系统(通常称为身份提供商或 IdP)中,然后该系统管理凭据并颁发令牌或会话数据,以跨其他服务(称为服务提供商或 SP)验证用户身份).
单点登录如何工作?
增强的用户体验:用户只需一次登录即可访问多项服务,减少摩擦并提高可用性。
提高安全性:
简化的用户管理:
时间和成本效率:
合规与审核:
单点故障:
复杂的实现:
安全风险:
供应商锁定:
代币管理挑战:
企业应用:
云服务:
客户门户:
合作伙伴集成:
API 充当身份提供商 (IdP)。它对用户进行身份验证并颁发 JWT 令牌进行访问。
下面是所提供代码的结构化细分,为您的关注者解释了每个部分的目的。这是如何在 API 层实现 SSO 功能的可靠示例。
此设置中使用了以下软件包:
dotenv.config(); const SECRET_KEY = process.env.SECRET_KEY || "secret";
app.use( cors({ origin: ["http://localhost:5173", "http://localhost:5174"], credentials: true, }) ); app.use(express.json()); app.use(cookieParser());
模拟数据模拟用户及其关联的待办事项。
用户拥有角色(管理员或用户)和基本个人资料信息。
待办事项链接到用户 ID 以进行个性化访问。
用户成功登录后会收到包含 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" }); } });
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" }); } });
确保用户可以通过清除令牌来安全注销。
dotenv.config(); const SECRET_KEY = process.env.SECRET_KEY || "secret";
app.use( cors({ origin: ["http://localhost:5173", "http://localhost:5174"], credentials: true, }) ); app.use(express.json()); app.use(cookieParser());
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" }); } });
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" }); } });
app.post("/logout", (req, res) => { res.clearCookie("sso_token"); res.json({ message: "Logout successful" }); });
主应用程序充当服务提供商 (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" }); } });
外部应用程序充当另一个服务提供商 (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 path="/todos" element={isLoggedIn ? <Todos /> : <Navigate to={"/"} />} /> </Routes> </div> ); } export default App;
单点登录 (SSO) 简化了跨多个应用程序的用户身份验证和访问管理,从而增强了用户体验、安全性和运营效率。通过集中身份验证并利用基于安全令牌的机制,组织可以简化用户访问、降低与密码相关的风险并提高合规性和审核能力。
虽然 SSO 提供了众多好处,但它也带来了挑战,例如单点故障、复杂的实施要求、安全风险和潜在的供应商锁定。组织必须仔细规划和实施 SSO 解决方案,以减轻这些风险并最大限度地发挥集中式身份验证的优势。
通过遵循最佳实践、利用既定协议并选择开放标准,组织可以成功实施 SSO,以增强其应用程序和系统的用户体验、安全性和运营效率。
以上是单点登录 (SSO):React 和 ExpressJS 综合指南的详细内容。更多信息请关注PHP中文网其他相关文章!