[nest.js] jwt token 과 cookie 를 이용한 login 구현
jwt 를 이용하여 인증하는 api application은 local test가 불편하다.
인증시 token이 bearer token 형태일 경우
postman 에서 매번 login 후 token 값 알아내기 -> api 마다 수동으로 token 값 넣기 식으로 진행된다.
cookie 에 token 을 넣고 알아서 인증단계를 거치면 이런 노가다가 필요없다.
사전준비
패키지를 설치해 준다.
npm i --save cookie-parser
npm i --save-dev @types/cookie-parser
npm i --save @nestjs/jwt @nestjs/passport passport passport-jwt
main.ts 에 cookie parser 를 사용하도록 설정한다.
app.use( cookieParser() );
tsconfig.json 아래 내용을 추가해 준다.
"esModuleInterop": true
jwt strategy 작성
cookieExtractor 라는 함수만 보면 된다. 내용은 request 의 cookie 에 저장된 token 에 접근하는 것이다.
import { Injectable, NotFoundException, UnauthorizedException } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { ExtractJwt, Strategy } from "passport-jwt";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { User } from "../user/user.entity";
let cookieExtractor = function( req )
{
var token = null;
if ( req && req.cookies )
{
token = req.cookies["Authentication"] || req.header;
}
return token;
};
@Injectable()
export class JwtStrategy extends PassportStrategy( Strategy )
{
constructor( @InjectRepository( User ) private userRepository : Repository<User> )
{
super( {
secretOrKey : process.env.JWT_SECRET || jwtConfig.get( "secret" ),
jwtFromRequest : cookieExtractor
} );
}
async validate( payload ) : Promise<UserDTO>
{
const { id } = payload;
// const uid : string = payload["uid"];
const user : UserDTO = await this.userService.findOne( { id : id } );
if( !user )
throw new UnauthorizedException( 'not user' );
return user;
}
}
auth.module.ts 에 import 추가
PassportModule.register( { defaultStrategy : "jwt" } ),
JwtModule.register
(
{
secret : process.env.JWT_SECRET_KEY
signOptions : { expiresIn : process.env.EXPIRES_IN }
}
),
login 시 cookie 에 token 저장
controller 의 response 객체에 jwt service로 발급받은 token 을 저장한다
@Post( '/login' )
async login(
@Body( ValidationPipe ) dto: UserDTO,
@Res( { passthrough : true } ) res : Response
) : Promise<object>
{
const accessToken : object = await this.authService.login( dto );
res.cookie(
'Authentication',
accessToken['token'],
{
domain : 'localhost',
path : '/',
httpOnly : true,
maxAge : 0.5 * 60 * 60 * 1000//0.5 hour
}
);
return accessToken;
}
async login( dto: UserDTO ): Promise<object>
{
.
.
.
const payload = { id : user.id }
const token = await this.jwtService.sign( payload );
return {
'msg' : 'ok',
'token' : token
};
}
사용예시
@UseGuards decorator 로 주입된 controller 함수를 사용할 경우 자동으로 인증처리가 된다.
@Get( '/myinfo' )
@UseGuards( AuthGuard() )
getUser( @GetUser() user : User ) : User
{
return user;
}