16.Next.js와 Nest.js로 사용자 인증 구현하기, JWT(Json Web Token)를 활용한 사용자 인증 시스템

웹 애플리케이션에서 사용자 인증은 매우 중요한 요소입니다. 이 글에서는 Next.jsNest.js를 사용하여 JWT(Json Web Token)를 활용한 사용자 인증 시스템을 구현하는 방법에 대해 자세히 설명합니다.

목차

1. 사용자 인증이란?

사용자 인증은 사용자가 누구인지 확인하는 프로세스입니다. 일반적으로 로그인 및 로그아웃 기능을 통해 사용자의 신원을 확인합니다. 이 과정은 애플리케이션의 보안성을 높이는 중요한 요소입니다. 인증에는 서버와 클라이언트 간에 정보를 교환하는 여러 가지 방법이 있으며, 가장 널리 사용되는 방법 중 하나는 JWT(Json Web Token)를 사용하는 것입니다.

2. JWT란?

JWT는 JSON 객체를 안전하게 전송하기 위한 개방형 표준입니다. JWT는 세 부분으로 구성된 문자열로, 각각 헤더(Header), 페이로드(Payload), 서명(Signature)로 나뉩니다.

  • 헤더(Header): 토큰의 유형과 해싱 알고리즘을 지정합니다.
  • 페이로드(Payload): 사용자의 정보와 권한을 포함하는 데이터입니다.
  • 서명(Signature): 헤더와 페이로드의 정보를 기반으로 생성된 해시 값으로, 토큰의 무결성을 확인합니다.

JWT의 주요 장점은 클라이언트 측에서 정보를 저장하고 이를 검증할 수 있는 점입니다. 또한 상태 비저장(stateless) 방식으로 서버의 부담을 최소화할 수 있습니다.

3. 환경 설정

이 프로젝트를 진행하기 위해서는 Node.js와 npm(Node Package Manager)이 필요합니다. 다음 링크에서 이를 설치할 수 있습니다: Node.js 공식 웹사이트

4. Nest.js 프로젝트 설정

Nest.js는 프레임워크를 통해 서버 사이드 애플리케이션을 구축하기 위한 강력한 도구입니다. 다음은 Nest.js 프로젝트를 설정하는 방법입니다.

npm install -g @nestjs/cli
nest new auth-example
cd auth-example
npm install @nestjs/jwt passport-jwt passport bcryptjs class-validator class-transformer

위 명령을 사용하여 Nest.js 프로젝트를 생성하고 필요한 라이브러리를 설치합니다.

4.1. 모듈 생성

인증 기능을 위한 모듈을 생성합니다. 다음 명령어를 사용합니다.

nest g module auth
nest g service auth
nest g controller auth

이 명령어는 auth 모듈, 서비스, 및 컨트롤러를 각각 생성합니다.

4.2. AuthService 구현

AuthService는 사용자의 등록 및 로그인을 처리하는 서비스입니다. 아래와 같이 auth.service.ts 파일을 수정합니다.

import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { User } from 'src/user/user.entity'; // 예시를 위한 User 모델
import * as bcrypt from 'bcryptjs';

@Injectable()
export class AuthService {
    constructor(private jwtService: JwtService) {}

    async register(userData: any): Promise {
        const hashedPassword = await bcrypt.hash(userData.password, 10);
        const user = new User();  // 사용자를 DB에 저장하는 로직 필요
        user.username = userData.username;
        user.password = hashedPassword;
        // save user to DB logic
        return user;
    }

    async validateUser(username: string, password: string): Promise {
        const user = await this.findUserByUsername(username); // 사용자를 DB에서 찾는 로직 필요
        if (user && await bcrypt.compare(password, user.password)) {
            return user;
        }
        return null;
    }

    async login(user: any) {
        const payload = { username: user.username, sub: user.userId };
        return {
            access_token: this.jwtService.sign(payload),
        };
    }
}

4.3. AuthController 구현

인증 관련 HTTP 요청을 처리하는 AuthController 를 구현합니다.

import { Controller, Post, Request, UseGuards } from '@nestjs/common';
import { AuthService } from './auth.service';
import { LocalAuthGuard } from './local-auth.guard'; // 로컬 인증 가드

@Controller('auth')
export class AuthController {
    constructor(private readonly authService: AuthService) {}

    @Post('register')
    async register(@Request() req) {
        return this.authService.register(req.body);
    }

    @UseGuards(LocalAuthGuard)
    @Post('login')
    async login(@Request() req) {
        return this.authService.login(req.user);
    }
}

4.4. JWT 설정

JWT를 사용할 수 있도록 설정합니다.

import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';

@Module({
    imports: [
        JwtModule.register({
            secret: 'secretKey', // 환경변수로 분리할 것
            signOptions: { expiresIn: '60s' }, // 토큰 만료 시간
        }),
    ],
    controllers: [AuthController],
    providers: [AuthService],
})
export class AuthModule {}

5. Next.js 프로젝트 설정

Next.js는 React 기반으로 서버 사이드 렌더링을 지원하는 프레임워크입니다. 다음은 Next.js 프로젝트를 설정하는 방법입니다.

npx create-next-app next-auth-example
cd next-auth-example
npm install axios js-cookie

5.1. 로그인 페이지 생성

Next.js 프로젝트에 로그인 기능을 추가합니다. pages/login.js 파일을 만들고 아래와 같이 수정합니다.

import { useState } from 'react';
import axios from 'axios';
import Cookies from 'js-cookie';

const Login = () => {
    const [username, setUsername] = useState('');
    const [password, setPassword] = useState('');

    const handleLogin = async () => {
        try {
            const response = await axios.post('http://localhost:3000/auth/login', { username, password });
            Cookies.set('token', response.data.access_token);
            alert('로그인 성공');
        } catch (error) {
            alert('로그인 실패');
        }
    };

    return (
        

로그인

setUsername(e.target.value)} placeholder="사용자명" /> setPassword(e.target.value)} placeholder="비밀번호" />
); }; export default Login;

5.2. 사용자 인증 상태 관리

사용자 인증 상태를 관리하고, 인증이 필요한 페이지를 보호하는 방법을 살펴보겠습니다.

import { useEffect } from 'react';
import Router from 'next/router';
import Cookies from 'js-cookie';

const withAuth = (WrappedComponent) => {
    return (props) => {
        useEffect(() => {
            const token = Cookies.get('token');
            if (!token) {
                Router.push('/login');
            }
        }, []);

        return ;
    };
};

export default withAuth;

이렇게 구현하면 인증되지 않은 사용자가 특정 페이지에 접근할 때 로그인 페이지로 리디렉션됩니다.

6. 인증 구현

지금까지 설정한 내용을 바탕으로 전체적인 인증 흐름을 요약합니다. 사용자가 로그인 요청을 보내면 Nest.js의 AuthService가 해당 요청을 처리하게 됩니다. 사용자가 존재하고 비밀번호가 올바르게 입력되면 JWT 토큰을 발급받고, 이를 클라이언트는 쿠키에 저장합니다. 이후 요청은 이 토큰을 사용하여 인증된 사용자로서 처리됩니다.

이와 같이 Next.js와 Nest.js를 활용하면 효율적이고 안전한 사용자 인증 시스템을 구축할 수 있습니다.

7. 결론

본 글에서는 Next.js와 Nest.js를 이용하여 JWT 기반의 사용자 인증 시스템을 구현하는 방법에 대해 살펴보았습니다. 이러한 방법을 통해 현대의 웹 애플리케이션에서 필수적인 사용자 관리와 보안 기능을 효과적으로 개발할 수 있습니다. 앞으로 더 나아가 다양한 인증 방식 및 보안 관련 기능들도 고려해 보는 것이 좋습니다.

이 글이 여러분의 웹 개발 여정에 도움이 되기를 바랍니다. 질문이 있으시면 댓글로 남겨주세요!