1. refresh-token
리프레시 토큰이란? access-token이 탈취를 당했을 경우 보안에 취약한 점을 보완 하기 위해 존재.
2. 적용
cookie에 refresh-token을 저장 하기 위해 설치 할 프로그램
$ npm install --save cookie-parser
$ npm install --save-dev @types/cookie-parser
import * as cookieParser from 'cookie-parser';
app.use(cookieParser());
import { Injectable, UnauthorizedException } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import * as bcrypt from "bcrypt";
import { CreateUserDto } from "./dto/create-user.dto";
import { User } from "./user.entity";
import { LoginUserDto } from "./dto/login-uiser.dto";
import { JwtService } from "@nestjs/jwt";
import { Response } from "express";
@Injectable()
export class UserService {
constructor(
@InjectRepository(User)
private readonly userRepository: Repository<User>,
private readonly jwtService: JwtService
){}
async create(createUserDto: CreateUserDto):Promise<User> {
const {email, password} = createUserDto;
const hashedPassword = await bcrypt.hash(password, 10);
const result = await this.userRepository.save({
email,
password: hashedPassword
});
return result
}
async login(loginUserDto: LoginUserDto, res: Response) {
const {email, password} = loginUserDto;
const user = await this.findOneUser(email);
if(!user) throw new UnauthorizedException("이메일과 비밀번호를 확인해 주세요.");
const isPasswordCompare = await bcrypt.compare(password, user.password);
if(!isPasswordCompare) throw new UnauthorizedException("이메일과 비밀번호를 확인해 주세요");
this.setRefreshToken(user, res);
return this.getAccessToken(user);
}
private setRefreshToken(user: User, res: Response) {
const payload = { email: user.email, sub: user.id };
const refresh_token = this.jwtService.sign(
{payload},
{secret: 'secret', expiresIn: '1h'}
);
res.cookie('refresh_token', refresh_token, {
httpOnly: true,
maxAge: 30 * 24 * 60 * 60 * 1000
});
}
private getAccessToken(user: User) {
const payload = { email: user.email, sub: user.id };
const access_token = this.jwtService.sign(
{payload},
{secret: 'secret', expiresIn: '1h'}
)
return access_token
}
async findOneUser(email: string): Promise<User> | null {
return await this.userRepository.findOne({where: {email}, select: {email:true, id:true}});
}
findMe(): string {
return "qqqq"
}
}
쿠키에 정상적으로 저장 되고 있다.
3. restore-token
로그인시 access-token과 refresh-token모두 발급해 주었다. 이제 refresh토큰을 가지고 있을경우 access-token을 재발급 해주는 로직을 짜보자
export class LocalRefreshToken extends PassportStrategy(Strategy, "local-refresh-jwt") {
constructor() {
super({
jwtFromRequest: (req: Request) => {
console.log(req.headers.cookie);
},
secretOrKey: "secret",
})
}
async validate(payload) {
return payload;
}
}
import { Module } from "@nestjs/common";
import { JwtModule } from "@nestjs/jwt";
import { TypeOrmModule } from "@nestjs/typeorm";
import { LocalAccessToken, LocalRefreshToken } from "src/commons/auth/jwt-local.strategy";
import { UserController } from "./user.controller";
import { User } from "./user.entity";
import { UserService } from "./user.service";
@Module({
imports: [
TypeOrmModule.forFeature([User]),
JwtModule.register({}),
],
providers: [
UserService,
LocalAccessToken,
LocalRefreshToken
],
controllers: [
UserController,
]
})
export class UserModule {}
@UseGuards(AuthGuard("local-refresh-jwt"))
@Get('restore')
async resotreToken() {
return 'asdfasdfasdf'
}
파싱 해서 validate로 던져주자
export class LocalRefreshToken extends PassportStrategy(Strategy, "local-refresh-jwt") {
constructor() {
super({
jwtFromRequest: (req: Request) => {
return req.cookies['refresh_token']
},
secretOrKey: "secret",
})
}
async validate(payload) {
return payload;
}
}
@UseGuards(AuthGuard("local-refresh-jwt"))
@Get('restore')
async resotreToken(@Req() req) {
return await this.userService.getAccessToken(req.user);
}