π 곡λΆνλ μ§μ§μνμΉ΄λ μ²μμ΄μ§?
[Nest JS λ‘ CRUD κ²μν λ§λ€κΈ°] (28) Passport, JWT λ₯Ό μ΄μ©ν΄μ ν ν° μΈμ¦ ν μ μ μ 보 κ°μ Έμ€κΈ° λ³Έλ¬Έ
[Nest JS λ‘ CRUD κ²μν λ§λ€κΈ°] (28) Passport, JWT λ₯Ό μ΄μ©ν΄μ ν ν° μΈμ¦ ν μ μ μ 보 κ°μ Έμ€κΈ°
μ§μ§μνμΉ΄ 2023. 6. 9. 11:12<λ³Έ λΈλ‘κ·Έλ 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