프로그래밍/Nest.js

인증 및 인가: Nest.js에서의 안전한 웹 애플리케이션 구축

shimdh 2025. 3. 22. 10:11
728x90

웹 애플리케이션의 보안은 현대 디지털 환경에서 매우 중요한 요소입니다. 특히, 인증(Authentication)과 인가(Authorization)는 사용자의 신원을 확인하고, 특정 자원에 대한 접근 권한을 부여하는 과정으로, 웹 애플리케이션의 안전성을 보장하는 데 필수적입니다. 이번 포스트에서는 Nest.js를 활용하여 인증 및 인가 전략을 구현하는 방법에 대해 자세히 알아보겠습니다.

인증(Authentication)

인증은 사용자가 자신이 주장하는 사람임을 증명하는 과정입니다. 일반적으로 사용자 이름과 비밀번호를 통해 이루어지며, 사용자가 성공적으로 인증을 받으면 서버는 해당 사용자에게 토큰을 발급합니다. 이 토큰은 이후의 요청에서 신원을 증명하는 데 사용됩니다.

JWT(JSON Web Token) 기반 인증

  • 사용자가 로그인할 때, 서버는 입력된 자격 증명을 검증합니다. 이 과정은 사용자의 비밀번호가 데이터베이스에 저장된 해시와 일치하는지를 확인하는 방식으로 이루어집니다.
  • 검증이 완료되면, 서버는 JWT를 생성하여 클라이언트에게 반환합니다. 이 토큰은 사용자의 신원을 확인하는 데 필요한 정보를 포함하고 있으며, 클라이언트는 이후 요청 시 이 토큰을 포함하여 서버에 요청함으로써 자신의 신원을 증명하게 됩니다.
// AuthService.ts
import { Injectable } from '@nestjs/common';
import * as jwt from 'jsonwebtoken';

@Injectable()
export class AuthService {
    async login(user: any) {
        const payload = { username: user.username, sub: user.userId };
        return {
            access_token: jwt.sign(payload, 'secretKey', { expiresIn: '60s' }),
        };
    }
}

인가(Authorization)

인가란 인증된 사용자가 특정 자원이나 기능에 접근할 수 있는지를 결정하는 과정입니다. 이는 보통 역할 기반 액세스 제어(RBAC)를 통해 이루어지며, 각 사용자에게 부여된 역할에 따라 접근 가능한 리소스를 제한합니다. 이러한 인가 과정은 웹 애플리케이션의 보안성을 더욱 강화하는 데 기여합니다.

역할 기반 인가

  • 각 사용자에게 역할(Role)을 부여하고, 해당 역할에 따라 접근 가능한 리소스를 제한합니다. 예를 들어, 관리자는 모든 리소스에 접근할 수 있지만 일반 사용자는 일부 리소스만 접근할 수 있도록 설정할 수 있습니다. 이를 통해 시스템의 보안을 더욱 강화할 수 있습니다.
// roles.guard.ts
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';

@Injectable()
export class RolesGuard implements CanActivate {
    constructor(private reflector: Reflector) {}

    canActivate(context: ExecutionContext): boolean {
        const roles = this.reflector.get<string[]>('roles', context.getHandler());
        if (!roles) {
            return true;
        }

        const request = context.switchToHttp().getRequest();
        const user = request.user;

        return roles.includes(user.role);
    }
}

인증 전략 구현

Nest.js에서는 Passport 모듈을 활용하여 다양한 인증 전략을 손쉽게 구현할 수 있습니다. JWT 외에도 OAuth2와 같은 다른 인증 방식을 사용할 수 있으며, 이를 통해 다양한 요구 사항에 맞는 인증 시스템을 구축할 수 있습니다.

단계별 설명

  1. Passport 설치:

    npm install @nestjs/passport passport passport-jwt
  2. JWT 전략 설정:

    // jwt.strategy.ts
    import { Injectable } from '@nestjs/common';
    import { PassportStrategy } from '@nestjs/passport';
    import { ExtractJwt, Strategy } from 'passport-jwt';
    
    @Injectable()
    export class JwtStrategy extends PassportStrategy(Strategy) {
        constructor() {
            super({
                jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
                secretOrKey: 'secretKey',
            });
        }
    
        async validate(payload: any) {
            return { userId: payload.sub, username: payload.username };
        }
    }
  3. 모듈 내에서 적용:

    // auth.module.ts 
    import { Module } from '@nestjs/common';
    import { JwtModule } from '@nestjs/jwt';
    import { AuthService } from './auth.service';
    import { JwtStrategy } from './jwt.strategy';
    
    @Module({
        imports:[
          JwtModule.register({
              secret:'secretKey',
              signOptions:{expiresIn:'60s'},
          }),
        ],
        providers:[AuthService, JwtStrategy],
    })
    export class AuthModule {}
  4. 컨트롤러에서 보호하기:

    // app.controller.ts 
    import { Controller, Get, UseGuards } from '@nestjs/common';
    import { AuthGuard } from '@nestjs/passport';
    
    @Controller('app')
    export class AppController {
    
        @UseGuards(AuthGuard('jwt'))
        @Get('protected')
        getProtectedResource() {
            return "This is a protected resource!";
         }
    }

결론

인증 및 인가는 Nest.js 애플리케이션의 안전성을 높이는 데 필수적입니다. JWT와 같은 기술들을 활용하면 효율적이고 안전한 방식으로 사용자 관리를 할 수 있으며, 이를 통해 더 나은 사용자 경험과 시스템 안정성을 제공할 수 있습니다. Roles와 Guards를 적절히 조합해 필요한 부분만 보호하도록 설계하면 더욱 효과적인 보안을 구축할 수 있습니다. 이러한 접근 방식은 웹 애플리케이션의 전반적인 보안 수준을 향상시키고, 사용자 데이터의 안전성을 보장하는 데 기여합니다.

728x90