다음으로 jwt(jason web token) 구현을 위한 준비입니다. import jwtConstants와 관련된 부분이에요.
auth폴더 아래에 'constants.ts' 파일을 추가하여 아래와 같이 구현합니다. jwt를 생성할 때 사용하는 시크릿 키로 외부에 노출되면 안 되는 부분입니다.
export const jwtConstants = {
secret: 'secretKey', // token 발급 시 사용되는 시크릿 키. 노출되면 안됨.
};
마지막으로 JwtStrategy를 위해 'jwt.strategy'를 생성해줍니다. LocalStrategy처럼 JWT를 위한 PassportStrategy확장형 JwtStrategy입니다.
local에서는 매핑할 filed 정도만 정의해 주었는데 jwt에서는 여러 가지 정보가 있어요. 상세 내용은 주석을 참고하세요.
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(), // Request에서 JWT를 추출하는 방법 중 Bearer Token 사용
ignoreExpiration: false, // jwt 보증을 passport 모듈에 위임함. 만료된 JWT인경우 request거부, 401 response
secretOrKey: jwtConstants.secret, // token 발급에 사용할 시크릿 키
});
}
async validate(payload: any) {
return { userId: payload.sub, userEmail: payload.userEmail };
}
}
여기까지 import 된 부분에 대한 설명이었고, auth.module의 imports를 보면 UsersModule, PassportModule을 가져왔고 JwtModule은 register를 통해 등록하였어요. register() 안쪽 부분이 JwtModule에 대한 Options이에요.
auth module까지 끝났고요. 이제 guards에 대한 부분을 구현해 보도록 하겠습니다.
Guards의 역할은 request가 처리될지 말지를 결정합니다. 예를 들어 로그인에 정상적으로 성공한 경우 이후의 프로세스를 실행할 수 있지만, 로그인에 실패한 경우 더 이상 접근할 수 없도록 하는 것이지요.
'app.controllers.ts'를 열어 수정해줍니다. app.으로 왔다니 뭔가 끝이 보이는 거 같네요.
import { Controller, Request, Get, Post, UseGuards } from '@nestjs/common';
import { ApiOperation, ApiParam } from '@nestjs/swagger';
import { AuthGuard } from '@nestjs/passport';
import { get } from 'http';
import { AppService } from './app.service';
import { AuthService } from './auth/auth.service';
import { JwtAuthGuard } from './auth/jwt-auth.guard';
import { LocalAuthGuard } from './auth/local-auth.guard';
@Controller('auth')
export class AppController {
constructor(
private authService: AuthService,
private appService: AppService,
) {}
// @UseGuards(AuthGuard('local'))
@UseGuards(LocalAuthGuard)
@Post('/login')
async login(@Request() req) {
// return req.user;
return this.authService.login(req.user);
}
@UseGuards(JwtAuthGuard)
@Get('/profile')
getProfile(@Request() req) {
return req.user;
}
@Get('/helloworld')
getHello(): string {
return this.appService.getHello();
}
@Get('/health')
@ApiOperation({
summary: 'auth health check',
description: 'auth application 이 정상 상태인지 체크한다.',
})
getHealth(): string {
return this.appService.getHealth();
}
}
guard에 대한 부분도 strategy와 같이 local, jwt가 있어요.
먼저 'local-auth.guard.ts'를 구현합니다.
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class LocalAuthGuard extends AuthGuard('local') {}
'jwt-auth.guard.ts'
import {
ExecutionContext,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
canActivate(context: ExecutionContext) {
// Add your custom authentication logic here
// for example, call super.logIn(request) to establish a session.
return super.canActivate(context);
}
handleRequest(err, user, info) {
// You can throw an exception based on either "info" or "err" arguments
if (err || !user) {
throw err || new UnauthorizedException();
}
return user;
}
}