ref. https://docs.nestjs.com/recipes/passport#implementing-passport-jwt
Documentation | NestJS - A progressive Node.js framework
Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Rea
docs.nestjs.com
https://docs.nestjs.com/security/authentication -> 이 문서에서는 AuthGuard 라는 이름의 커스텀 Guard 를 작성하여 사용했으나
@nestJs/passport 패키지에서 제공하는 AuthGuard('jwt') 를 가져와서 Guard 로 사용한다는 차이가 있다.
0. 패키지 설치
npm install --save @nestjs/passport passport passport-jwt
npm install --save-dev @types/passport-jwt
(공식문서 내용)
For **any** Passport strategy you choose, you'll always need the `@nestjs/passport` and `passport` packages. Then, you'll need to install the strategy-specific package (e.g., `passport-jwt` or `passport-local`) that implements the particular authentication strategy you are building. In addition, you can also install the type definitions for any Passport strategy, as shown above with `@types/passport-local`, which provides assistance while writing TypeScript code.
1. auth.service.ts
(Authentication 1/2 내용과 동일)
login 시에 JWT 토큰을 발급하여 리턴한다.
@Injectable()
export class AuthService {
constructor(
private datasource: DataSource,
private jwtService: JwtService,
@InjectRepository(Authentication)
private authRepository: Repository<Authentication>,
) {}
async login(signInDto: signInDto): Promise<{ access_token: string }> {
const auth = await this.authRepository.findOneBy({
email: signInDto.email,
});
if (auth?.password !== signInDto.password) {
throw new UnauthorizedException();
}
const payload = { sub: auth.id, authEmail: auth.email };
return {
access_token: await this.jwtService.signAsync(payload),
};
}
2. jwt.strategy.ts 구현, auth.module.ts 일부 수정
jwt.strategy.ts
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: process.env.JWT_CONSTANTS,
});
}
async validate(payload: any) {
// Passport will build a `user` object based on the return value of our `validate()` method,
// and attach it as a property on the `Request` object.
// auth.service.ts
// const payload = { sub: auth.id, authEmail: auth.email };
return { authId: payload.sub, authEmail: payload.authEmail };
}
}
auth.module.ts 에 JwtStrategy 추가
@Module({
imports: [
TypeOrmModule.forFeature([Authentication]),
JwtModule.register({
// registering the JwtModule as global to make things easier for us.
// This means that we don't need to import the JwtModule anywhere else in our application.
global: true,
secret: process.env.JWT_CONSTANTS,
signOptions: {
expiresIn: '600s', // token expiration time
},
}),
],
providers: [AuthService, JwtStrategy],
controllers: [AuthController],
exports: [AuthService],
})
export class AuthModule {}
3. jwt-auth.guard.ts
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}
4. auth.controller.ts
@UseGuards(JwtAuthGuard)
@Patch('password')
async updateAccount(
@Body() updateAccountDto: UpdateAccountDto,
@Request() req,
): Promise<UpdateResult> {
console.log(req.user);
return await this.authService.changePassword(updateAccountDto);
}
원하는 범위에 구현한 JwtAuthGuard 를 추가
JwtGuard 는 이전 포스팅인 Authentication 1/2 에서 구현한 AuthGuard 와 동일하게
request 의 헤더에서 jwt 토큰값을 읽어와서 유효성을 검사하고, validation 함수를 실행하여 validation 함수의 반환값을
request 객체의 user 프로퍼티에 추가한다. (request.user)
##
auth.controller.ts
console.log(req.user) 실행결과 예시
{
authId: '61b2dc24-9d07-4730-a5ab-9ab2df9a811b',
authEmail: 'O^^O@naver.com'
}