首页 web前端 js教程 单点登录 (SSO):React 和 ExpressJS 综合指南

单点登录 (SSO):React 和 ExpressJS 综合指南

Jan 06, 2025 am 01:17 AM

单点登录 (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 存储库
演示视频

Single Sign-On (SSO): A Comprehensive Guide with React and ExpressJS

单点登录 (SSO)

单点登录 (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
          path="/todos"
          element={isLoggedIn ? <Todos /> : <Navigate to={"/"} />}
        />
      </Routes>
    </div>
  );
}

export default App;
登录后复制

结论

单点登录 (SSO) 简化了跨多个应用程序的用户身份验证和访问管理,从而增强了用户体验、安全性和运营效率。通过集中身份验证并利用基于安全令牌的机制,组织可以简化用户访问、降低与密码相关的风险并提高合规性和审核能力。

虽然 SSO 提供了众多好处,但它也带来了挑战,例如单点故障、复杂的实施要求、安全风险和潜在的供应商锁定。组织必须仔细规划和实施 SSO 解决方案,以减轻这些风险并最大限度地发挥集中式身份验证的优势。

通过遵循最佳实践、利用既定协议并选择开放标准,组织可以成功实施 SSO,以增强其应用程序和系统的用户体验、安全性和运营效率。

以上是单点登录 (SSO):React 和 ExpressJS 综合指南的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

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

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

前端热敏纸小票打印遇到乱码问题怎么办? 前端热敏纸小票打印遇到乱码问题怎么办? Apr 04, 2025 pm 02:42 PM

前端热敏纸小票打印的常见问题与解决方案在前端开发中,小票打印是一个常见的需求。然而,很多开发者在实...

神秘的JavaScript:它的作用以及为什么重要 神秘的JavaScript:它的作用以及为什么重要 Apr 09, 2025 am 12:07 AM

JavaScript是现代Web开发的基石,它的主要功能包括事件驱动编程、动态内容生成和异步编程。1)事件驱动编程允许网页根据用户操作动态变化。2)动态内容生成使得页面内容可以根据条件调整。3)异步编程确保用户界面不被阻塞。JavaScript广泛应用于网页交互、单页面应用和服务器端开发,极大地提升了用户体验和跨平台开发的灵活性。

谁得到更多的Python或JavaScript? 谁得到更多的Python或JavaScript? Apr 04, 2025 am 12:09 AM

Python和JavaScript开发者的薪资没有绝对的高低,具体取决于技能和行业需求。1.Python在数据科学和机器学习领域可能薪资更高。2.JavaScript在前端和全栈开发中需求大,薪资也可观。3.影响因素包括经验、地理位置、公司规模和特定技能。

JavaScript难以学习吗? JavaScript难以学习吗? Apr 03, 2025 am 12:20 AM

学习JavaScript不难,但有挑战。1)理解基础概念如变量、数据类型、函数等。2)掌握异步编程,通过事件循环实现。3)使用DOM操作和Promise处理异步请求。4)避免常见错误,使用调试技巧。5)优化性能,遵循最佳实践。

如何使用JavaScript将具有相同ID的数组元素合并到一个对象中? 如何使用JavaScript将具有相同ID的数组元素合并到一个对象中? Apr 04, 2025 pm 05:09 PM

如何在JavaScript中将具有相同ID的数组元素合并到一个对象中?在处理数据时,我们常常会遇到需要将具有相同ID�...

如何实现视差滚动和元素动画效果,像资生堂官网那样?
或者:
怎样才能像资生堂官网一样,实现页面滚动伴随的动画效果? 如何实现视差滚动和元素动画效果,像资生堂官网那样? 或者: 怎样才能像资生堂官网一样,实现页面滚动伴随的动画效果? Apr 04, 2025 pm 05:36 PM

实现视差滚动和元素动画效果的探讨本文将探讨如何实现类似资生堂官网(https://www.shiseido.co.jp/sb/wonderland/)中�...

JavaScript的演变:当前的趋势和未来前景 JavaScript的演变:当前的趋势和未来前景 Apr 10, 2025 am 09:33 AM

JavaScript的最新趋势包括TypeScript的崛起、现代框架和库的流行以及WebAssembly的应用。未来前景涵盖更强大的类型系统、服务器端JavaScript的发展、人工智能和机器学习的扩展以及物联网和边缘计算的潜力。

console.log输出结果差异:两次调用为何不同? console.log输出结果差异:两次调用为何不同? Apr 04, 2025 pm 05:12 PM

深入探讨console.log输出差异的根源本文将分析一段代码中console.log函数输出结果的差异,并解释其背后的原因。�...

See all articles