ホームページ > ウェブフロントエンド > jsチュートリアル > Node.js で認証を行う正​​しい方法 [uide]

Node.js で認証を行う正​​しい方法 [uide]

Barbara Streisand
リリース: 2024-12-12 20:08:17
オリジナル
652 人が閲覧しました

The Right Way to do Authentication in Node.js [uide]

認証は、バックエンド開発において最も重要であるにもかかわらず誤解されがちな側面の 1 つです。その複雑さのため、開発者は Auth0 や Supabase などのサードパーティ ソリューションを頻繁に利用します。これらは優れたツールですが、独自の認証システムを構築すると、柔軟性と制御が向上します。

このガイドでは、依存関係を最小限に抑えた Express.js API サービス用のシンプルな認証ミドルウェアを実装する方法を学習します。最後には次のものが得られます:

  • 完全に機能するユーザー名パスワード認証。
  • ユーザー アカウントを保存するための PostgreSQL との統合。
  • JWT ベースの認証ミドルウェア。
  • 自動再利用検出を使用してトークンを更新し、セキュリティを強化します。

このガイドはシンプルさに重点を置き、複雑さを軽減するためにパスポート.js などのパッケージの使用を避けています。


ユーザーアカウントテーブルの設定

まず、ユーザー アカウントを保存するための PostgreSQL テーブルを作成します。

CREATE TABLE users (
    "id" SERIAL PRIMARY KEY,
    "username" VARCHAR(255) UNIQUE NOT NULL,
    "password" VARCHAR(255) NOT NULL,
    "email" VARCHAR(255) UNIQUE,
    "created_at" TIMESTAMP NOT NULL DEFAULT NOW()
);
ログイン後にコピー

JWT認証ミドルウェア

次に、API エンドポイントを保護するための JWT 認証ミドルウェアを作成します。この例では対称暗号化を使用します。マイクロサービス アーキテクチャの場合は、公開キーと秘密キーのペアを使用した非対称暗号化の使用を検討してください。

ミドルウェア コード (/src/middleware/jwt.ts):

import jwt from "jsonwebtoken";

const JWT_SECRET_KEY = process.env.JWT_SECRET_KEY as string; // Randomly generated. Min length: 64 characters

export const protectedRoute: RequestHandler = async (req, _, next) => {
  const authHeader = req.header("authorization");

  if (!authHeader) {
    return next(notAuthenticated());
  }

  const accessToken = authHeader.replace(new RegExp("\b[Bb]earer\s"), "");

  try {
    const { userId } = validateJWT(accessToken);
    const user = await userRepository.getUserById(parseInt(userId));

    if (user) {
      req.user = user;
      next();
    } else {
      next(invalidAccessToken());
    }
  } catch (err) {
    next(invalidAccessToken());
  }
};

const validateJWT = (token: string, verifyOptions?: jwt.VerifyOptions) => {
  const jwtVerifyOptions = Object.assign(
    { algorithms: "HS256" },
    verifyOptions,
    {
      issuer: "yourAPI.com",
      audience: "yourAPI.com:client",
    }
  );
  return jwt.verify(token, JWT_SECRET_KEY, jwtVerifyOptions) as T;
};
ログイン後にコピー

ミドルウェアを使用してルートを保護します:

import { protectedRoute } from "@/middleware/jwt";

router.get("/user", protectedRoute, async (req, res, next) => {
  const user = req.user!;
  res.json({ user });
});
ログイン後にコピー

認証コントローラーの作成

次に、サインアップとログイン用のコントローラーを実装します。

サインアップコントローラー:

import argon from "argon2";

const signup = async (props) => {
  const { username, password, email } = props;

  await userRepo.getUser(username).then((res) => {
    if (res !== null) throw usernameNotAvailable();
  });

  const hashedPass = await argon.hash(password, {
    timeCost: 2,
    parallelism: 1,
    memoryCost: 19456,
  });

  const newUser = await createUser({
    username,
    hashedPass,
    email,
  });

  const refreshToken = await generateRefreshToken(newUser.userId);
  const accessToken = generateAccessToken(newUser.userId);

  const { password: _, ...userRes } = newUser;
  return { user: userRes, accessToken, refreshToken };
};
ログイン後にコピー

ログインコントローラー:

const login = async (props) => {
  const { username, password } = props;

  const user = await getUser(username).then((res) => {
    if (res === null) throw invalidLoginCredentials();
    return res;
  });

  const isOk = await argon.verify(user.password, password);

  if (isOk) {
    const refreshToken = await generateRefreshToken(user.userId);
    const accessToken = generateAccessToken(user.userId);

    const { password: _, ...userRes } = user;
    return { user: userRes, accessToken, refreshToken };
  }

  throw invalidLoginCredentials();
};
ログイン後にコピー

リフレッシュトークンの保存

リフレッシュ トークンは長期的な認証を提供します。それらを保存するデータベース テーブルを作成しましょう:

CREATE TABLE refresh_tokens (
    "id" SERIAL PRIMARY KEY,
    "token" UUID NOT NULL DEFAULT gen_random_uuid(),
    "token_family" UUID NOT NULL DEFAULT gen_random_uuid(),
    "user_id" INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    "active" BOOLEAN DEFAULT true,
    "expires_at" TIMESTAMP NOT NULL,
    "created_at" TIMESTAMP NOT NULL DEFAULT NOW()
);
ログイン後にコピー

トークンジェネレーター:

import jwt from "jsonwebtoken";

const JWT_SECRET_KEY = process.env.JWT_SECRET_KEY as string; // Randomly generated. Min length: 64 characters

const generateAccessToken = (userId: number) => {
  const jwtSignOptions = Object.assign(
    { algorithm: "HS256" },
    {},
    {
      issuer: "yourAPI.com",
      audience: "yourAPI.com:client",
    }
  );
  return jwt.sign({ userId: userId.toString() }, JWT_SECRET_KEY, jwtSignOptions);
};

const generateRefreshToken = async (userId: number, tokenFamily?: string) => {
  const expAt = new Date(new Date().getTime() + 31 * 24 * 60 * 60 * 1000); // Expire in 31 days
  const refreshTokenExp = expAt.toISOString();

  const token = await createTokenQuery({
    userId,
    tokenFamily,
    expiresAt: refreshTokenExp,
  });

  return token;
};
ログイン後にコピー

リフレッシュトークンロジック:

トークンのリフレッシュを安全に処理するロジックを実装します:

const refreshToken = async ({ token }: RefreshTokenSchema) => {
  const tokenData = await getRefreshToken(token);

  if (!tokenData) throw forbiddenError();

  const { userId, tokenFamily, active } = tokenData;

  if (active) {
    // Token is valid and hasn't been used yet
    const newRefreshToken = await generateRefreshToken(userId, tokenFamily);
    const accessToken = generateAccessToken(userId);

    return { accessToken, refreshToken: newRefreshToken };
  } else {
    // Previously refreshed token used, invalidate all tokens in family
    await invalidateRefreshTokenFamily(tokenFamily);

    throw forbiddenError();
  }
};
ログイン後にコピー

リフレッシュ トークンと自動再利用検出について詳しくは、この Auth0 の記事をご覧ください。


結論

このガイドに従うことで、依存関係を最小限に抑えた Node.js API 用のシンプルで安全な認証システムを構築できました。このアプローチにより、セキュリティを完全に制御し、最新のベスト プラクティスに準拠することが保証されます。

時間と労力を節約したい場合は、Vratix をチェックしてください。当社のオープンソース CLI は、認証を備えた完全に機能する Node.js プロジェクトを数秒でセットアップできます。 GitHub で完全に実装された認証モジュールをご覧ください。


このガイドは役に立ちましたか?コメント欄でお知らせいただくか、X でご連絡ください!

以上がNode.js で認証を行う正​​しい方法 [uide]の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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