KAKAO.GG
백엔드

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

65870717953200389e7820de
2024. 6. 12.
조회 121
#next js jwt, next js jwt 로그인, next.js 토큰 저장, Nextjs session 관리, Next JS JWT decode, Next.js auth

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

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를 구현할 수 있지만, 라이브러리를 사용해 빠르게 개발하는 것도 좋은 방법입니다.

 

Next.js JWT를 이용한 인증 구현하기 - Tech Data - KAKAO.GG