21.Nest.js와 Next.js에서 Middleware와 Guard 사용하기, 각 페이지별 접근 권한 설정

본 블로그 포스트에서는 Nest.js와 Next.js에서 Middleware와 Guard의 개념과 그 사용 방법에 대해 자세히 설명하겠습니다. 특히, 각 페이지별 접근 권한을 설정하는 방법에 대해서도 알아보겠습니다. 이 포스트를 통해 여러분은 Nest.js와 Next.js 환경에서 권한을 관리하고, 사용자 인증 및 인가를 효과적으로 구현할 수 있는 방법을 익히게 될 것입니다.

1. Nest.js에서 Middleware 이해하기

Nest.js는 Express.js 기반의 훌륭한 Node.js 프레임워크로, Middleware는 요청-응답 사이클에서 요청을 처리하는 중간 단계의 로직을 구성하는 데 사용됩니다. Middleware는 요청을 가로채어 처리하거나, 요청 객체를 변형하거나, 다음 Middleware로 요청을 전달할 수 있는 기능을 제공합니다.

1.1 Middleware의 용도

  • 로그인 여부 확인
  • 요청 기록 기록
  • 헤더 수정
  • 오류 처리

1.2 Nest.js에서 Middleware 구현하기

Nest.js에서는 Middleware를 클래스로 구현하고, 이를 모듈에서 등록하여 사용할 수 있습니다. 아래는 간단한 로그인 확인 Middleware의 예시입니다.


import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class AuthMiddleware implements NestMiddleware {
    use(req: Request, res: Response, next: NextFunction) {
        const token = req.headers.authorization;
        if (token) {
            // 인증 로직 (예: 디코딩 JWT)
            next();
        } else {
            res.status(403).send('Unauthorized');
        }
    }
}

위의 코드에서 `AuthMiddleware`는 요청에 포함된 토큰을 확인하고, 인증이 이루어지지 않은 경우 403 상태 코드를 반환합니다.

1.3 Middleware 등록하기

Middleware는 모듈에서 등록할 수 있습니다. 아래는 전체 모듈에 Middleware를 등록하는 방법입니다.


import { Module, MiddlewareConsumer, NestModule } from '@nestjs/common';
import { AuthMiddleware } from './auth.middleware';

@Module({
    // ...
})
export class AppModule implements NestModule {
    configure(consumer: MiddlewareConsumer) {
        consumer
            .apply(AuthMiddleware)
            .forRoutes('*'); // 모든 경로에 Middleware 적용
    }
}

2. Nest.js에서 Guard 사용하기

Guard는 요청 처리 전에 특정 조건(예: 권한)을 확인하는 데 사용됩니다. Guards는 다음 두 가지 주요 목적으로 사용됩니다.

  • 특정 경로 또는 핸들러에 대한 접근 권한 확인
  • 어떠한 요청을 처리할 수 있는지에 대한 조건을 설정

2.1 Guard의 정의 및 사용 방법

Nest.js의 Guards는 주로 `CanActivate` 인터페이스를 구현하여 생성합니다. 아래는 사용자의 역할 기반으로 접근을 제어하는 Guard의 예시입니다.


import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';

@Injectable()
export class RolesGuard implements CanActivate {
    canActivate(context: ExecutionContext): boolean {
        const request = context.switchToHttp().getRequest();
        const user = request.user; // 이전에 middleware에서 사용자 정보 설정
        const hasRole = () => user.roles.indexOf('admin') > -1;
        return user && user.roles && hasRole();
    }
}

2.2 Guard 등록 및 사용하기

Guard는 컨트롤러의 핸들러 또는 모듈에 더할 수 있습니다. 아래의 코드는 특정 컨트롤러에 Guard를 등록하는 예시입니다.


import { Controller, Get, UseGuards } from '@nestjs/common';
import { RolesGuard } from './roles.guard';

@Controller('admin')
export class AdminController {
    @Get()
    @UseGuards(RolesGuard)
    getAdminData() {
        return 'Admin Data';
    }
}

3. Next.js에서 Middleware 이해하기

Next.js에서 Middleware는 요청이 들어오는 단계에서 선처리하거나 특정 조건에 따라 사용자에게 응답할 수 있는 방법을 제공합니다. Next.js는 API Routes와 페이지에 Middleware를 적용할 수 있습니다.

3.1 Next.js Middleware의 용도

  • 사용자 인증
  • 404 처리
  • API 호출 간소화

3.2 Next.js에서 Middleware 활성화하기

Next.js 12 버전부터 제공되는 Middleware를 사용하여 각 라우트에 접근하기 전에 사용자 인증을 확인하는 예시입니다. Middleware는 `middleware.ts` 파일에서 정의합니다.


// middleware.ts
import { NextResponse } from 'next/server';

export function middleware(request) {
    const token = request.cookies.get('token');
    if (!token) {
        return NextResponse.redirect(new URL('/login', request.url));
    }
    return NextResponse.next();
}

4. Next.js에서 Guard 사용하기

Next.js에서는 Guard를 명시적으로 구현하는 방법은 없지만, 각 페이지에서 직접 사용자 인증을 처리할 수 있습니다. 예를 들어, 서버 사이드 렌더링(SSR)에서 페이지 접근 제어를 설정할 수 있습니다.

4.1 서버 사이드에서 접근 권한 검증하기

아래는 Next.js의 `getServerSideProps`를 사용하여 사용자의 인증 상태를 확인하는 예시입니다.


export async function getServerSideProps(context) {
    const { req } = context;
    const token = req.cookies.token;
    
    if (!token) {
        return {
            redirect: {
                destination: '/login',
                permanent: false,
            },
        };
    }

    // 사용자 데이터 fetch 등의 로직
    return {
        props: {}, // 성공적으로 인증된 경우 페이지에 전달할 데이터
    };
}

5. 결론

Nest.js와 Next.js에서 Middleware와 Guard를 활용함으로써 애플리케이션의 보안 및 유연성을 높일 수 있습니다. 각각의 기술 스택에서의 역할과 사용법을 깊이 있게 이해하고 있으면, 복잡한 인증 로직과 접근 권한 관리를 보다 효과적으로 구현할 수 있습니다. 이 포스트에서 다룬 내용을 바탕으로 여러분의 프로젝트에도 적절한 Middleware와 Guard를 적용하여 사용자 경험을 향상시키시길 바랍니다.