JWT 3. JWT 사용 시나리오

agnusdei·2023년 7월 28일
0
  1. JWT를 사용한 사용자 인증:
    사용자 인증은 사용자가 자신의 신원을 확인하여 시스템에 접근하는 것을 의미합니다. JWT는 사용자 인증에 효과적인 방법으로 사용됩니다.

    • 인증 과정:

      1. 사용자가 자격 증명(예: 사용자 이름과 비밀번호)을 제공하여 로그인을 시도합니다.
      2. 서버는 제공된 자격 증명을 검증하고, 유효한 경우에는 사용자에게 JWT를 발행합니다.
      3. 이후, 사용자는 발급된 JWT를 사용하여 서버에 접근하고 보호된 리소스에 접근할 수 있습니다.
    • JWT 구조:
      JWT는 기본적으로 세 부분으로 이루어집니다.

      • Header: JWT의 타입과 사용된 암호화 알고리즘이 포함됩니다.
      • Payload: 클레임(정보)이 포함되며, 사용자의 식별자와 권한 등 정보가 담겨 있습니다.
      • Signature: Header와 Payload를 인코딩한 후, 비밀 키로 서명한 값이 들어갑니다.
  2. JWT를 이용한 API 보안 인증:
    JWT는 API 보안 인증에 널리 사용되는 방법 중 하나로, 사용자가 API에 접근할 때 JWT를 포함시키는 인증 방식을 사용합니다.

    • 인증 과정:

      1. 사용자가 로그인을 하여 JWT를 발급받습니다.
      2. 이후, API 요청을 할 때마다 발급받은 JWT를 Authorization 헤더 등에 포함시켜 전송합니다.
      3. 서버는 해당 JWT를 검증하고, 유효한 경우에만 API 요청을 처리하고 응답합니다.
    • 장점:

      • 서버 측에서 별도의 세션 관리가 필요하지 않습니다.
      • 느슨한 결합(Loose coupling): 서버와 클라이언트 간에 독립적으로 동작할 수 있도록 해줍니다.
      • 확장성과 유연성이 좋습니다.
  3. JWT를 활용한 SSO (Single Sign-On):
    SSO는 여러 개의 서비스나 애플리케이션에 대해 한 번의 로그인으로 모두 접근할 수 있는 인증 방식입니다. JWT를 사용한 SSO는 각 서비스에서 독립적으로 인증하는 대신, 하나의 인증 서비스를 통해 한 번의 로그인으로 여러 서비스에 접근합니다.

    • 인증 과정:

      1. 사용자가 SSO 서비스에 로그인을 시도합니다.
      2. SSO 서비스는 사용자의 자격 증명을 검증하고, 인증된 사용자에게 JWT를 발행합니다.
      3. 이후, 다른 서비스에 접근할 때 해당 JWT를 사용자의 신원 확인에 사용합니다.
    • 장점:

      • 사용자는 여러 번의 로그인 과정 없이 편리하게 다양한 서비스를 이용할 수 있습니다.
      • 보안성이 향상됩니다. 사용자의 자격 증명은 한 곳에서만 관리되기 때문에 보안 위협이 줄어듭니다.

이러한 방식으로 JWT를 사용하여 사용자 인증, API 보안 인증, 그리고 SSO를 구현할 수 있습니다. 단, JWT를 사용할 때에는 토큰의 유효기간과 보안적인 측면을 고려하여 안전하고 효율적인 인증 시스템을 구성해야 합니다.

JWT를 사용한 사용자 인증:

설명:
사용자 인증은 사용자가 자신의 신원을 확인하여 시스템에 접근하는 것을 의미합니다. JWT는 사용자 인증에 효과적인 방법으로 사용됩니다.

코드 예시:

const jwt = require('jsonwebtoken');

// 사용자 로그인 시 JWT 발급 예시
function loginUser(req, res) {
  // 사용자 정보를 검증하고 유효한 사용자라면 사용자 ID로 JWT를 발급합니다.
  const user = {
    id: 123,
    username: 'user123',
    role: 'admin', // 사용자의 권한 등을 포함한 정보
  };

  // JWT 생성
  const token = jwt.sign(user, 'secret_key', { expiresIn: '1h' });

  res.json({ token });
}

// JWT를 이용한 사용자 인증 검증 미들웨어 예시
function authenticateToken(req, res, next) {
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1];

  if (!token) {
    return res.sendStatus(401); // Unauthorized
  }

  jwt.verify(token, 'secret_key', (err, user) => {
    if (err) {
      return res.sendStatus(403); // Forbidden
    }
    req.user = user;
    next();
  });
}

JWT를 이용한 API 보안 인증:

설명:
JWT는 API 보안 인증에 널리 사용되는 방법 중 하나로, 사용자가 API에 접근할 때 JWT를 포함시키는 인증 방식을 사용합니다.

코드 예시:

const express = require('express');
const jwt = require('jsonwebtoken');

const app = express();

// 미들웨어로 사용자 인증 검증
app.use(authenticateToken);

// 보호된 API 엔드포인트 예시
app.get('/protected-resource', (req, res) => {
  // 검증된 사용자 정보에 접근 가능
  const user = req.user;
  res.json({ message: 'This is a protected resource!', user });
});

// 사용자 인증 검증 미들웨어 예시
function authenticateToken(req, res, next) {
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1];

  if (!token) {
    return res.sendStatus(401); // Unauthorized
  }

  jwt.verify(token, 'secret_key', (err, user) => {
    if (err) {
      return res.sendStatus(403); // Forbidden
    }
    req.user = user;
    next();
  });
}

app.listen(3000, () => {
  console.log('Server running on http://localhost:3000');
});

JWT를 활용한 SSO (Single Sign-On):

설명:
SSO는 여러 개의 서비스나 애플리케이션에 대해 한 번의 로그인으로 모두 접근할 수 있는 인증 방식입니다. JWT를 사용한 SSO는 각 서비스에서 독립적으로 인증하는 대신, 하나의 인증 서비스를 통해 한 번의 로그인으로 여러 서비스에 접근합니다.

코드 예시:

const express = require('express');
const jwt = require('jsonwebtoken');

const app = express();

// SSO 서비스 로그인 예시
app.post('/sso/login', (req, res) => {
  // 사용자 정보를 검증하고 유효한 사용자라면 사용자 ID로 JWT를 발급합니다.
  const user = {
    id: 123,
    username: 'user123',
    role: 'admin', // 사용자의 권한 등을 포함한 정보
  };

  // JWT 생성
  const token = jwt.sign(user, 'sso_secret_key', { expiresIn: '1h' });

  res.json({ token });
});

// 다른 서비스에서 SSO 토큰을 이용한 인증 검증 미들웨어 예시
function authenticateToken(req, res, next) {
  const ssoToken = req.headers['sso-authorization'];
  
  if (!ssoToken) {
    return res.sendStatus(401); // Unauthorized
  }

  jwt.verify(ssoToken, 'sso_secret_key', (err, user) => {
    if (err) {
      return res.sendStatus(403); // Forbidden
    }
    req.user = user;
    next();
  });
}

app.listen(3000, () => {
  console.log('Server running on http://localhost:3000');
});

위의 코드 예시들은 간단한 노드js 서버를 구현한 것으로, 실제로 사용되는 시스템에서는 보안 및 에러 처리 등에 추가적인 구현이 필요할 수 있습니다. 실제 서비스에서는 보안에 신경을 써야 하며, 비밀 키 관리, HTTPS 사용 등을 고려해야 합니다.

NestJS에서 JWT 라이브러리를 사용하는 시나리오를 코드 예시와 함께 설명하겠습니다. NestJS에서는 @nestjs/jwt 패키지를 사용하여 JWT를 쉽게 구현할 수 있습니다.

먼저, NestJS 프로젝트를 설정하고 @nestjs/jwt 패키지를 설치해야 합니다.

npm install --save @nestjs/jwt

다음으로, NestJS 애플리케이션 모듈에 JwtModule을 등록하고 JWT의 시크릿 키와 유효성 검사 옵션을 설정해야 합니다.

// app.module.ts

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

@Module({
  imports: [
    JwtModule.register({
      secret: 'SECRET_KEY', // JWT를 암호화/복호화하는데 사용되는 시크릿 키
      signOptions: { expiresIn: '1h' }, // JWT 유효기간 설정 (예: 1시간)
    }),
  ],
  controllers: [AuthController],
  providers: [AuthService],
})
export class AppModule {}

이제 AuthService에서 로그인과 JWT 토큰 발행을 처리하는 로직을 구현해보겠습니다.

// auth/auth.service.ts

import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';

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

  // 사용자 로그인 로직 (DB와 연동하여 사용자 인증)
  async login(username: string, password: string) {
    const user = await this.validateUser(username, password);
    if (!user) {
      throw new Error('Invalid credentials');
    }

    // 로그인이 성공하면 JWT 토큰 발행
    const payload = { username: user.username, sub: user.userId };
    return {
      access_token: this.jwtService.sign(payload),
    };
  }

  // 사용자 인증 검증 (예시로 단순히 확인만 수행)
  async validateUser(username: string, password: string): Promise<any> {
    // 예시로 사용자를 하나 정의하고 인증 수행
    const user = { userId: 1, username: 'testuser', password: 'password' };
    return user.username === username && user.password === password ? user : null;
  }
}

마지막으로, AuthController에서 로그인 요청을 처리하고 JWT 토큰을 클라이언트에게 반환해줍니다.

// auth/auth.controller.ts

import { Controller, Post, Request, Body } from '@nestjs/common';
import { AuthService } from './auth.service';

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

  @Post('login')
  async login(@Body() body: any) {
    const { username, password } = body;
    return this.authService.login(username, password);
  }
}

이제 NestJS 애플리케이션에 JWT 인증이 구현되었습니다. 사용자가 POST /auth/login 엔드포인트에 유효한 자격 증명을 제공하면 서버에서 JWT 토큰을 발행하고 해당 토큰을 클라이언트에게 반환합니다. 클라이언트는 이후 보호된 API 엔드포인트에 JWT 토큰을 Authorization 헤더 등에 포함하여 요청을 보내어 인증될 수 있습니다. API 보호를 위해 Guards와 함께 사용할 수도 있습니다.

profile
DevSecOps ⚙️ + Pentest 🚩

0개의 댓글