Header Banner
GG Logo

Future Engineering

기술의 최전선을 기록합니다.

기술 자료/BackEnd/Next.js JWT를 이용한 인증 구현하기

Next.js JWT를 이용한 인증 구현하기

BackEnd약 1년 전

먼저 필요한 패키지를 설치합니다.

npm install jsonwebtoken bcryptjs

 

JWT와 bcrypt를 이용한 API 작성

app/api/auth/register.js

import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import { NextResponse } from 'next/server';
const users = []; // 실제 구현 시 데이터베이스 사용
export async function POST(request) {
    const { username, password } = await request.json();
    const hashedPassword = await bcrypt.hash(password, 10);
    const user = { id: Date.now(), username, password: hashedPassword };
    users.push(user);
    const token = jwt.sign({ id: user.id, username: user.username }, 'jwt_secret', {
        expiresIn: '1h',
    });
    return NextResponse.json({ token });
}

 

app/api/auth/login.js

import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import { NextResponse } from 'next/server';
const users = []; // 실제 구현 시 데이터베이스 사용
export async function POST(request) {
    const { username, password } = await request.json();
    const user = users.find(user => user.username === username);
    if (!user || !(await bcrypt.compare(password, user.password))) {
        return NextResponse.json({ error: 'Invalid username or password' }, { status: 401 });
    }
    const token = jwt.sign({ id: user.id, username: user.username }, 'jwt_secret', {
        expiresIn: '1h',
    });
    return NextResponse.json({ token });
}

 

로그인 및 회원가입 페이지 작성

app/login/page.js

'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
export default function LoginPage() {
    const [username, setUsername] = useState('');
    const [password, setPassword] = useState('');
    const router = useRouter();
    const handleSubmit = async (e) => {
        e.preventDefault();
        const res = await fetch('/api/auth/login', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({ username, password }),
        });
        if (res.ok) {
            const data = await res.json();
            localStorage.setItem('token', data.token);
            router.push('/');
        } else {
            alert('Invalid credentials');
        }
    };
    return (
        <form onSubmit={handleSubmit}>
            <input
                type="text"
                value={username}
                onChange={(e) => setUsername(e.target.value)}
                placeholder="Username"
                required
            />
            <input
                type="password"
                value={password}
                onChange={(e) => setPassword(e.target.value)}
                placeholder="Password"
                required
            />
            <button type="submit">Login</button>
        </form>
    );
}

 

app/register/page.js

'use client';
import { useState } from 'react';
import { useRouter } from 'next/navigation';
export default function RegisterPage() {
    const [username, setUsername] = useState('');
    const [password, setPassword] = useState('');
    const router = useRouter();
    const handleSubmit = async (e) => {
        e.preventDefault();
        const res = await fetch('/api/auth/register', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({ username, password }),
        });
        if (res.ok) {
            const data = await res.json();
            localStorage.setItem('token', data.token);
            router.push('/');
        } else {
            alert('Registration failed');
        }
    };
    return (
        <form onSubmit={handleSubmit}>
            <input
                type="text"
                value={username}
                onChange={(e) => setUsername(e.target.value)}
                placeholder="Username"
                required
            />
            <input
                type="password"
                value={password}
                onChange={(e) => setPassword(e.target.value)}
                placeholder="Password"
                required
            />
            <button type="submit">Register</button>
        </form>
    );
}

 

JWT 검증을 위한 미들웨어 작성

Next.js 14에서는 미들웨어를 사용하여 JWT를 검증할 수 있습니다.

middleware.js

import { NextResponse } from 'next/server';
import jwt from 'jsonwebtoken';
export async function middleware(request) {
    const token = request.headers.get('Authorization')?.split(' ')[1];
    if (!token) {
        return NextResponse.redirect(new URL('/login', request.url));
    }
    try {
        jwt.verify(token, 'jwt_secret');
        return NextResponse.next();
    } catch (err) {
        return NextResponse.redirect(new URL('/login', request.url));
    }
}
export const config = {
    matcher: ['/protected/*'],
};

 

로그인, 회원가입 페이지는 기본 디자인입니다. 최근에는 Next Auth 또는 Clerk와 같은 라이브러리를 사용하는 프로젝트가 많이 있습니다. JWT를 필요로 하는 서비스에서는 위 내용을 바탕으로 JWT를 구현할 수 있지만, 라이브러리를 사용해 빠르게 개발하는 것도 좋은 방법입니다.