😎 κ³΅λΆ€ν•˜λŠ” μ§•μ§•μ•ŒνŒŒμΉ΄λŠ” μ²˜μŒμ΄μ§€?

[Nest JS 둜 CRUD κ²Œμ‹œνŒ λ§Œλ“€κΈ°] (28) Passport, JWT λ₯Ό μ΄μš©ν•΄μ„œ 토큰 인증 ν›„ μœ μ € 정보 κ°€μ Έμ˜€κΈ° λ³Έλ¬Έ

πŸ‘©‍πŸ’» λ°±μ—”λ“œ(Back-End)/Nest js

[Nest JS 둜 CRUD κ²Œμ‹œνŒ λ§Œλ“€κΈ°] (28) Passport, JWT λ₯Ό μ΄μš©ν•΄μ„œ 토큰 인증 ν›„ μœ μ € 정보 κ°€μ Έμ˜€κΈ°

μ§•μ§•μ•ŒνŒŒμΉ΄ 2023. 6. 9. 11:12
728x90
λ°˜μ‘ν˜•

<λ³Έ λΈ”λ‘œκ·ΈλŠ” John Ahn μ˜ 유튜브λ₯Ό μ°Έκ³ ν•΄μ„œ κ³΅λΆ€ν•˜λ©° μž‘μ„±ν•˜μ˜€μŠ΅λ‹ˆλ‹€ :-)>

=> λ”°λΌν•˜λ©΄μ„œ λ°°μš°λŠ” NestJS

 

🧸 Passport, JWT λ₯Ό μ΄μš©ν•΄μ„œ ν† ν° μΈμ¦ ν›„ μœ μ € μ •λ³΄ κ°€μ Έμ˜€κΈ° 

JWT μ΄μš©ν•΄μ„œ μœ μ €κ°€ 둜그인 ν•  λ•Œ 토큰 생성

μœ μ €κ°€ μš”μ²­ 보낼 λ•Œ μš”μ²­ μ•ˆμ— μžˆλŠ” Header 에 토큰 λ„£μŒ (μš”μ²­ μ•ˆμ— Payload μž‡μŒ)

토큰이 μœ νš¨ν•œ 토큰인지 μ„œλ²„μ—μ„œ secret text μ΄μš©ν•˜μ—¬ μ•Œμ•„λ‚΄λ©΄, Payload μ•ˆμ— μœ μ € 이름 μ΄μš©ν•΄μ„œ λ°μ΄ν„°λ² μ΄μŠ€ μ•ˆμ˜ μœ μ € 정보λ₯Ό κ°€μ Έμ˜΄

=> μ΄λŸ¬ν•œ 처리λ₯Ό μ‰½κ²Œ ν•΄μ£ΌλŠ” λͺ¨λ“ˆμ΄ Passport

 

🧸 Passport 

//passport-jwt λͺ¨λ“ˆμ„ μœ„ν•œ νƒ€μž… μ •μ˜ λͺ¨λ“ˆ
@types/passport-jwt

npm install @types/passport-jwt --save

 

πŸŽ€ jwt.strategy.ts

import { Injectable, UnauthorizedException } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { InjectRepository } from "@nestjs/typeorm";
import { ExtractJwt, Strategy } from "passport-jwt";
import { UserRepository } from "./user.repository";
import { User } from "./user.entity";

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
    constructor(
        @InjectRepository(UserRepository)
        private userRepository: UserRepository
    ) {
        super({
            // JWT token in order to validate it
            // Access its payload
            secretOrKey: "Secret1234",
            // to look for the JWT in the Authorization Header of current Request
            // passed over as a Bearer token
            jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken()
        })
    }

    // 토큰이 μœ νš¨ν•œμ§€ 체크가 되면 validate λ©”μ†Œλ“œμ—μ„œ payload 에 μžˆλŠ” μœ μ € 이름이
    // λ°μ΄ν„°λ² μ΄μŠ€μ—μ„œ μžˆλŠ” μœ μ €μΈμ§€ 확인! μžˆλ‹€λ©΄ μœ μ € 객체 return
    // return @UseGuards(AuthGuard()) μ΄μš©ν•œ λͺ¨λ“  μš”μ²­μ˜ Request Object에 듀어감
    async validate(payload) {
        const {username} = payload;
        const user: User = await this.userRepository.findOne({username});

        if (!user) {
            throw new UnauthorizedException();
        }

        return user;
    }
}

 

πŸŽ€ auth.module.ts

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserRepository } from './user.repository';
import { AuthController } from './auth.controller';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';
import { JwtStrategy } from './jwt.strategy';
import { Passport } from 'passport';

@Module({
  imports: [
    PassportModule.register({ defaultStrategy: "jwt"}),
    JwtModule.register({
      // 토큰을 λ§Œλ“€ λ•Œ μ΄μš©ν•˜λŠ” Secret ν…μŠ€νŠΈ
      secret: "Secret1234", // μ•„λ¬΄κ±°λ‚˜ 해도 됨
      signOptions: {
        // 정해진 μ‹œκ°„ μ΄ν›„μ—λŠ” 토큰이 μœ νš¨ν•˜μ§€ μ•Šκ²Œ 됨 (60 * 60 은 ν•œμ‹œκ°„)
        expiresIn: 60 * 60,
      }
    }),
    TypeOrmModule.forFeature([UserRepository])
  ],
  controllers: [AuthController],
  providers: [AuthService, JwtStrategy],
  // λ‹€λ₯Έ κ³³μ—μ„œλ„ μ‚¬μš©ν•΄μ•Ό ν•˜λ―€λ‘œ exports..
  exports: [JwtStrategy, PassportModule]
})
export class AuthModule {}

 

πŸŽ€ auth.controller.ts

import { Body, Controller, Post, Req, UseGuards, ValidationPipe } from '@nestjs/common';
import { AuthService } from './auth.service';
import { AuthCredentialsDto } from './dto/auth-credential.dto';
import { AuthGuard } from '@nestjs/passport';

@Controller('auth')
export class AuthController {
    constructor( private authService: AuthService) {}
    
    // localhost:3000/auth/signUp
    @Post("/signup")
    // ValidationPipe : μš”μ²­μ΄ μ»¨νŠΈλ‘€λŸ¬μ— μžˆλŠ” ν•Έλ“€λŸ¬λ‘œ 듀어왔을 λ•Œ Dto 에 μžˆλŠ” μœ νš¨μ„± 쑰건에 맞게 체크
    signUp(@Body(ValidationPipe) authCredentialsDto: AuthCredentialsDto): Promise<void> {
        return this.authService.signUp(authCredentialsDto);
    }
    
    // 둜그인 κΈ°λŠ₯ κ΅¬ν˜„ν•˜κΈ°
    @Post("/signin")
    signIn(@Body(ValidationPipe) authCredentialsDto: AuthCredentialsDto): Promise<{accessToken: string}> {
        return this.authService.signIn(authCredentialsDto);
    }

    // TEST
    @Post("/authTest")
    // 인증 미듀웨어
    // μ§€μ •λœ 경둜둜 톡과할 수 μžˆλŠ” μ‚¬λžŒκ³Ό ν—ˆμš©ν•˜μ§€ μ•ŠλŠ” μ‚¬λžŒμ„ μ„œλ²„μ— μ•Œλ €μ€Œ
    @UseGuards(AuthGuard())
    test(@Req() req) {
        console.log("req ", req);
    }

}

 

🧸 μš”μ²­ μ•ˆμ— μœ μ € 정보(객체) κ°€ λ“€μ–΄κ°€λŠ” 방법

validate λ©”μ†Œλ“œμ—μ„œ return 값을 user 객체둜 함

 

πŸŽ€ UseGuards

UsesGuards μ•ˆμ— @nestjs/passport μ—μ„œ κ°€μ Έμ˜¨ AuthGuard() μ΄μš©ν•˜λ©΄ μš”μ²­ μ•ˆμ— μœ μ € 정보 넣을 수 있음

 

🧸 Nest 의 Middleware

πŸŽ€ Pipes

: μš”μ²­ μœ νš¨μ„± 검사 및 νŽ˜μ΄λ‘œλ“œ λ³€ν™˜μ„ μœ„ν•΄ λ§Œλ“€μ–΄μ§

: 데이터λ₯Ό μ˜ˆμƒν•œ λŒ€λ‘œ 직렬화

 

πŸŽ€ Filters

: 였λ₯˜ 처리 미듀웨어

: νŠΉμ • 였λ₯˜ 처리기λ₯Ό μ‚¬μš©ν•  κ²½λ‘œμ™€ 각 경둜 μ£Όλ³€μ˜ λ³΅μž‘μ„±μ„ 관리

 

πŸŽ€ Guards

: 인증 미듀웨어

: μ§€μ •λœ 경둜둜 톡과할 수 μžˆλŠ” μ‚¬λžŒκ³Ό ν—ˆμš©ν•˜μ§€ μ•ŠλŠ” μ‚¬λžŒμ„ μ„œλ²„μ— μ•Œλ €μ€Œ

 

πŸŽ€ Interceptors

: 응닡 맀핑 및 μΊμ‹œ 관리와 ν•¨κ»˜ μš”μ²­ λ‘œκΉ…κ³Ό 같은 μ „ν›„ 미듀웨어

🚩 각각 미듀웨어 λΆˆλŸ¬μ§€λŠ” μˆœμ„œ
middleware -> guard -> interceptor (before) -> pipe -> controller -> service -> controller -> interceptor (after) -> filter (if applicable) -> client
728x90
λ°˜μ‘ν˜•
Comments