ホームページ > ウェブフロントエンド > jsチュートリアル > シングル サインオン (SSO): React と ExpressJS の包括的なガイド

シングル サインオン (SSO): React と ExpressJS の包括的なガイド

Susan Sarandon
リリース: 2025-01-06 01:17:07
オリジナル
855 人が閲覧しました

シングル サインオン (SSO) は、ユーザーが一度ログインすると、接続されている複数のアプリケーションやシステムにそれぞれ再認証することなくアクセスできるようにする認証メカニズムです。 SSO は、ユーザー認証を単一の信頼できるシステム (アイデンティティ プロバイダー (IdP) と呼ばれることが多い) に集中させ、そのシステムが資格情報を管理し、トークンまたはセッション データを発行して、他のサービス (サービス プロバイダー (SP) と呼ばれる) 間でユーザーの ID を検証します。

このガイドでは、SSO の仕組み、その利点と欠点、一般的な使用例、API (Express を使用した Node.js)、メイン アプリケーション (React)、および外部アプリケーションでの SSO 実装の例について説明します。アプリケーション(React)。 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) と呼ばれる) 全体でユーザーの ID を検証します。 ).

SSO はどのように機能しますか?

SSO は、OAuth 2.0、OpenID Connect (OIDC)、または Security Assertion Markup Language (SAML) などの安全なトークンベースのメカニズムを通じて動作します。簡略化されたフローは次のとおりです:

  • ユーザー ログイン: ユーザーはアイデンティティ プロバイダー (IdP) に資格情報を入力します。

  • トークン発行: IdP は資格情報を検証し、認証トークン (JWT または SAML アサーションなど) を発行します。

  • サービス アクセス: トークンはサービス プロバイダーに渡され、サービス プロバイダーがそれを検証し、追加のログインを必要とせずにアクセスを許可します。

SSO の利点

  • ユーザー エクスペリエンスの強化: ユーザーは 1 回のログインで複数のサービスにアクセスできるため、煩雑さが軽減され、使いやすさが向上します。

  • セキュリティの向上:

    • パスワードの再利用などの安全でない行為につながる可能性のあるパスワード疲労を軽減します。
    • 一元化された認証により、より強力なパスワード ポリシーと多要素認証 (MFA) の強制が可能になります。
  • 簡素化されたユーザー管理:

    • 管理者は、接続されているアプリケーション全体でのユーザー アクセスを管理しやすくなります。
    • IdP からユーザーへのアクセスを取り消すと、すべての統合システムへのアクセスが無効になります。
  • 時間とコストの効率:

    • ログイン関連のヘルプデスクへのリクエストを減らすことで、ユーザーとサポートチームの時間を節約します。
    • 既存の認証メカニズムを活用することで、開発時間とコストを削減します。
  • コンプライアンスと監査:

    • 一元化された認証とアクセス制御により、セキュリティ ポリシーの適用とユーザー アクティビティの追跡が容易になります。

SSO の欠点

  • 単一障害点:

    • IdP が利用できないか侵害されている場合、ユーザーは接続されているシステムにアクセスできません。
    • 軽減策: 冗長 IdP を使用し、高可用性を確保します。
  • 複雑な実装:

    • SSO の統合には、特に多様なアプリケーションやプロトコルが存在する環境では、重要な計画と専門知識が必要です。
    • 軽減策: OAuth 2.0 や SAML などの確立されたプロトコルと堅牢な SSO ライブラリを活用します。
  • セキュリティリスク:

    • 攻撃者がユーザーの SSO 認証情報にアクセスすると、接続されているすべてのシステムにアクセスできる可能性があります。
    • 軽減策: 強力な MFA を適用し、不審なログイン アクティビティを監視します。
  • ベンダーロックイン:

    • 組織は特定の IdP ベンダーに大きく依存している場合があり、移行が困難になります。
    • 緩和策: オープンスタンダードを選択し、独自のソリューションを避けてください。
  • トークン管理の課題:

    • トークンの有効期限が切れたり盗まれたりすると、アクセスが中断されたり、セキュリティ上の脆弱性が生じたりする可能性があります。
    • 緩和策: トークンの有効期限、更新メカニズム、安全なトークン ストレージを実装します。

SSO の使用例

  • エンタープライズ アプリケーション:

    • 従業員は 1 回のログインでさまざまな社内ツールやサービスにアクセスできます。
    • オンボーディングおよびオフボーディングのプロセスを簡素化します。
  • クラウド サービス:

    • ユーザーはログインを繰り返すことなく、クラウド アプリケーションをシームレスに切り替えることができます。
    • 生産性とユーザー エクスペリエンスを向上させます。
  • カスタマーポータル:

    • さまざまなサービスにわたる顧客に統一されたログイン エクスペリエンスを提供します。
    • パーソナライゼーションとターゲットを絞ったマーケティングを可能にします。
  • パートナー統合:

    • パートナー組織間の共有リソースへの安全なアクセスを容易にします。
    • コラボレーションとデータ交換を合理化します。

SSOの実装例

1. API (Express を使用した Node.js)

API はアイデンティティ プロバイダー (IdP) として機能します。ユーザーを認証し、アクセス用の JWT トークンを発行します。

以下は、提供されたコードの構造化された内訳であり、フォロワー向けに各セクションの目的を説明しています。これは、API レイヤーに SSO 機能を実装する方法の確実な例として機能します。

セットアップと依存関係

このセットアップでは次のパッケージが使用されます:

  • express: HTTP リクエストとルーティングの処理用。
  • jsonwebtoken: JWT の生成と検証用。
  • cors: 異なるクライアント アプリケーションからのクロスオリジン リクエストを処理します。
  • @faker-js/faker: 模擬ユーザーと Todo データの生成用。
  • 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());
ログイン後にコピー
ログイン後にコピー

ユーザー認証とトークン生成

モック データは、ユーザーとユーザーに関連付けられた ToDo をシミュレートします。

ユーザーにはロール (管理者またはユーザー) と基本的なプロフィール情報があります。
Todo はユーザー 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: トークンをデコードしてユーザーの 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" });
  }
});
ログイン後にコピー
ログイン後にコピー
  • /logout: JWT トークンを含む Cookie をクリアします。

トークンをクリアすることで、ユーザーが安全にログアウトできるようにします。

dotenv.config();
const SECRET_KEY = process.env.SECRET_KEY || "secret";
ログイン後にコピー
ログイン後にコピー
  • /todos: 認証されたユーザーに関連付けられた todos を取得します。
app.use(
  cors({
    origin: ["http://localhost:5173", "http://localhost:5174"],
    credentials: true,
  })
);
app.use(express.json());
app.use(cookieParser());
ログイン後にコピー
ログイン後にコピー
  • /todos: 認証されたユーザーの新しい todo を追加します。
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 に基づいて todo を更新します。
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 に基づいて todo を削除します。
app.post("/logout", (req, res) => {
  res.clearCookie("sso_token");
  res.json({ message: "Logout successful" });
});
ログイン後にコピー

2. メインアプリケーション(React)

メイン アプリケーションは、API を使用してユーザー インタラクションを管理するサービス プロバイダー (SP) として機能します。

以下は、提供されたコードの構造化された内訳であり、フォロワー向けに各セクションの目的を説明しています。これは、メイン アプリケーション層に SSO 機能を実装する方法の確実な例として機能します。

  • アプリコンポーネント

アプリ コンポーネントはユーザー認証を管理し、ログイン ステータスに基づいてリダイレクトします。

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 コンポーネント

Todos コンポーネントはユーザー固有の Todo を表示し、Todo の追加と削除を可能にします。

// 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)

外部アプリケーションは、API を使用してユーザー操作を管理する別のサービス プロバイダー (SP) として機能します。

以下は、提供されたコードの構造化された内訳であり、フォロワー向けに各セクションの目的を説明しています。これは、外部アプリケーション層に SSO 機能を実装する方法の確実な例として機能します。

  • アプリコンポーネント

アプリ コンポーネントはユーザー認証を管理し、ログイン ステータスに基づいてリダイレクトします。

// 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 コンポーネント

Todos コンポーネントには、ユーザー固有の Todo が表示されます。

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 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート