JWT Strategy 적용
JWT 인증을 위한 패키지 설치
$ npm install --save @nestjs/jwt passport-jwt
$ npm install --save-dev @types/passport-jwt
- @nestjs에서 passport 사용할 수 있게 해주는 패키지
- passport-jwt : jwt 전략을 실행하기 위한 passport 패키지
- @types/passport-jwt : jwt 전략을 구현할 때 타입스크립트 코드 작성을 도와줌
AuthService Login 메소드 작성
auth/auth.service.ts
- jwtService 인스턴스 AuthService에 생성자를 통해 주입
- local 전략을 통해 반환된 유저 정보를 토대로 payload를 구성
- jwtSerivce sign 메소드를 통해 액세스 토큰 생성 및 반환
import { Injectable } from '@nestjs/common';
import { UserService } from 'src/user/user.service';
import { JwtService } from '@nestjs/jwt';
import * as bcrypt from 'bcrypt';
@Injectable()
export class AuthService {
constructor(
private userService: UserService,
private jwtService: JwtService,
) {}
async validateUser(email: string, password: string): Promise<any> {
const user = await this.userService.findOneByEmail(email);
const validatePassword = await bcrypt.compare(password, user.password);
if (user && validatePassword) {
const { password, ...result } = user;
return result;
}
return null;
}
async login(user: any) {
const payload = { username: user.name, sub: user.id };
return {
access_token: this.jwtService.sign(payload),
};
}
}
AuthModule에 JwtModule 추가
auth/constants.ts
export const jwtConstants = {
secret: 'secretKey',
};
auth/auth.module.ts
- JwtModule register 메소드를 통해 secret key와 토큰 만료 시간 등록
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { LocalStrategy } from './local.strategy';
import { JwtStrategy } from './jwt.strategy';
import { UserModule } from '../user/user.module';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';
import { jwtConstants } from './constants';
@Module({
imports: [
UserModule,
PassportModule,
JwtModule.register({
secret: jwtConstants.secret,
signOptions: { expiresIn: '1d' },
}),
],
providers: [AuthService, LocalStrategy],
exports: [AuthService],
})
export class AuthModule {}
Login route가 access token을 반환하도록 업데이트
app.controller.ts
import { Controller, Request, Get, Post, UseGuards } from '@nestjs/common';
import { AppService } from './app.service';
import { AuthService } from './auth/auth.service';
import { LocalAuthGuard } from './auth/local-auth.guard';
@Controller()
export class AppController {
constructor(private authService: AuthService) {}
@UseGuards(LocalAuthGuard)
@Post('auth/login')
async login(@Request() req) {
return this.authService.login(req.user);
}
}
jwt.strategy.ts 파일 생성
auth/jwt.strategy.ts
- 클라이언트가 토큰을 보냈을 때 토큰 검증하는 로직을 수행
- 검증을 성공하면 페이로드의 유저 아이디와 유저이름을 req.user에 담아 return
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common';
import { jwtConstants } from './constants';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: jwtConstants.secret,
});
}
async validate(payload: any) {
return { userId: payload.sub, username: payload.username };
}
}
AuthModule에 JwtStrategy 추가
auth/auth.module.ts
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { LocalStrategy } from './local.strategy';
import { JwtStrategy } from './jwt.strategy';
import { UserModule } from '../user/user.module';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';
import { jwtConstants } from './constants';
@Module({
imports: [
UserModule,
PassportModule,
JwtModule.register({
secret: jwtConstants.secret,
signOptions: { expiresIn: '1d' },
}),
],
providers: [AuthService, LocalStrategy, JwtStrategy],
exports: [AuthService],
})
export class AuthModule {}
JWT 전략 실행
JwtAuthGuard 클래스 생성
auth/jwt-auth.guard.ts
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}
유저 인증이 필요한 API에 사용
user.controller.ts
@UseGuards(JwtAuthGuard)
@Get('/:id')
getUser(@Param('id') id: number) {
return this.userService.findOne(id);
}
@UseGuards(JwtAuthGuard)
@Patch()
updateUser(@Request() req, @Body() data: UpdateUserDto) {
return this.userService.update(req.user.userId, data);
}
@UseGuards(JwtAuthGuard)
@Delete()
deleteUser(@Request() req) {
return this.userService.remove(req.user.userId);
}
}