> 웹 프론트엔드 > JS 튜토리얼 > Node.js에서 인증을 수행하는 올바른 방법 [uide]

Node.js에서 인증을 수행하는 올바른 방법 [uide]

Barbara Streisand
풀어 주다: 2024-12-12 20:08:17
원래의
639명이 탐색했습니다.

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

인증은 백엔드 개발에서 가장 중요하지만 종종 오해를 받는 측면 중 하나입니다. 복잡성으로 인해 개발자는 Auth0 또는 Supabase와 같은 타사 솔루션을 자주 사용합니다. 이는 훌륭한 도구이지만 자체 인증 시스템을 구축하면 더 큰 유연성과 제어 기능을 제공할 수 있습니다.

이 가이드에서는 종속성을 최소화하면서 Express.js API 서비스를 위한 간단한 인증 미들웨어를 구현하는 방법을 알아봅니다. 최종적으로는 다음을 얻게 됩니다.

  • 완전히 작동하는 사용자 이름 비밀번호 인증.
  • PostgreSQL과 통합하여 사용자 계정을 저장합니다.
  • JWT 기반 인증 미들웨어입니다.
  • 보안 강화를 위해 자동 재사용 감지 기능으로 토큰을 새로 고칩니다.

이 가이드는 단순성에 중점을 두고 있으며 복잡성을 줄이기 위해 Passport.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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿