TIL( NestJS - Passport )

2024. 7. 5. 23:06ใ†TIL

๐Ÿ’กPassport

 

1.์˜์˜

- Passport๋Š” ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ๋Š” node.js ์ธ์ฆ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ, ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ๊ฐ€์žฅ ์ž˜ ์•Œ๋ ค์ ธ ์žˆ์œผ๋ฉฐ ๋งŽ์€ ํ”„๋กœ๋•์…˜ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์„ฑ๊ณต์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ๋‹ค.

- @nestjs/passport ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜์—ฌ NestJS์—์„œ ์ธ์ฆ๋กœ์ง์„ ๊น”๋”ํ•˜๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

2.ํŠน์ง•

- ๋‹ค์–‘ํ•œ ์ธ์ฆ ๋ฐฉ์‹ ์‚ฌ์šฉ๊ฐ€๋Šฅ : Passport๋Š” ๋กœ์ปฌ ๋กœ๊ทธ์ธ, OAuth, JWT ๋“ฑ ๋‹ค์–‘ํ•œ ์ธ์ฆ ๋ฐฉ์‹์„ ์ง€์›ํ•œ๋‹ค.

- ๋ฏธ๋“ค์›จ์–ด๋ฅผ ๊ธฐ๋ฐ˜ : Express ๋ฏธ๋“ค์›จ์–ด๋กœ ๋™์ž‘ํ•˜๋ฉฐ, NestJS์˜ ๋ฏธ๋“ค์›จ์–ด์™€ ์‰ฝ๊ฒŒ ํ†ตํ•ฉ๊ฐ€๋Šฅํ•˜๋‹ค.

- ์œ ์—ฐ์„ฑ : ์‚ฌ์šฉ์ž ์ •์˜ ์ „๋žต์„ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

3. NestJS์—์„œ Passport ์‚ฌ์šฉํ•˜๊ธฐ

  - ๋กœ๊ทธ์ธํ•˜๊ณ  JWTํ† ํฐ ๋ฐœ๊ธ‰๋ฐ›๊ธฐ

 

1) ์ƒˆ ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

nest new newproject

 

2) ํ•„์š”ํ•œ ํŒจํ‚ค์ง€ ์„ค์ •

npm install @nestjs/passport passport passport-local @nestjs/jwt passport-jwt

 

3)  Module ์ƒ์„ฑ

- Auth ๋ชจ๋“ˆ ์ƒ์„ฑ

nest g module auth
nest g service auth
nest g controller auth

 

4) JWT ์ „๋žต ์„ค์ •

//  auth/jwt.strategy.ts
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(private readonly configService: ConfigService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: false,
      secretOrKey: configService.get<string>('JWT_SECRET'),
    });
  }

  async validate(payload: any) {
    return { userId: payload.sub, username: payload.username };
  }
}

 

5) AuthService ์„ค์ •

// auth/auth.service.ts
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';

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

  async login(user: any) {
    const payload = { username: user.username, sub: user.userId };
    return {
      access_token: this.jwtService.sign(payload),
    };
  }
}

 

6) Auth ๋ชจ๋“ˆ ์„ค์ •

//  auth/auth.module.ts
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { PassportModule } from '@nestjs/passport';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
import { JwtStrategy } from './jwt.strategy';
import { ConfigModule, ConfigService } from '@nestjs/config';

@Module({
  imports: [
    PassportModule,
    JwtModule.registerAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: async (configService: ConfigService) => ({
        secret: configService.get<string>('JWT_SECRET'),
        signOptions: { expiresIn: '60s' },
      }),
    }),
  ],
  providers: [AuthService, JwtStrategy],
  controllers: [AuthController],
})
export class AuthModule {}

 

7) AuthController ์„ค์ •

//  auth/auth.controller.ts 
import { Controller, Post, Request, UseGuards } from '@nestjs/common';
import { AuthService } from './auth.service';
import { LocalAuthGuard } from './local-auth.guard';

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

  @UseGuards(LocalAuthGuard)
  @Post('login')
  async login(@Request() req) {
    return this.authService.login(req.user);
  }
}

 

8) LocalAuthGuard ์„ค์ •

//   auth/local-auth.guard.ts 
import { Injectable, ExecutionContext } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {
  async canActivate(context: ExecutionContext): Promise<boolean> {
    const result = (await super.canActivate(context)) as boolean;
    const request = context.switchToHttp().getRequest();
    await super.logIn(request);
    return result;
  }
}

 

9) UsersService ์„ค์ •

//   users/users.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class UsersService {
  private readonly users = [
    {
      userId: 1,
      username: 'test',
      password: 'test',
    },
  ];

  async findOne(username: string): Promise<any> {
    return this.users.find(user => user.username === username);
  }
}

 

10) LocalStrategy ์„ค์ •

// auth/local.strategy.ts
import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
  constructor(private readonly authService: AuthService) {
    super();
  }

  async validate(username: string, password: string): Promise<any> {
    const user = await this.authService.validateUser(username, password);
    if (!user) {
      throw new UnauthorizedException();
    }
    return user;
  }
}

 

 

 

 

 

 

 

 

 

'TIL' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

TIL (SQL๋ฌธ๋ฒ• - JOIN )  (0) 2024.07.09
TIL ( Injection )  (0) 2024.07.08
TIL( Nest.js - IoC, DI )  (0) 2024.07.04
TIL (DTO)  (0) 2024.07.03
TIL( TypeScript - Utility type )  (0) 2024.07.02