처음에는 이전 팀 프로젝트에서 처럼 AccessToken 만료시, /refresh를 할 때 RefreshToken을 검증하고 새로운 accesstoken을 발급했다.
전에 프론트에서 refreshToken을 사용했다면
이번에는 백엔드에서 refreshtoken을 사용해서 다양한 로직을 실험하게됬다.
새로 로그인을 하면 다른 곳에서 로그인 상태라면? 리프레쉬 토큰 자체가 만료됬다면? 오류로 인해 토큰이 없다면? 등 고려했을 때 더 많은 로직이 필요할 것 같지만 일단은 3가지 관문을 만들고 문제가 없다면 정상적인 accessToken을 발급 받을 수 있도록 했다.
처음에는 변수들이 많아서 axios로 요청시 cancelToken ERROR가 콘솔에 찍혔다
그 변수들을 다 참고 했을때 (3가지 관문) 드디어 에러 없이 토큰이 만료되면 재발급 가능해졌다
async refreshToken(user: Users, refreshToken: string): Promise<String> {
//1.레디스에 없을때
let RTfromRedis = await this.client.get(`${user.userId}:RT`);
if (!RTfromRedis) {
RTfromRedis = await this.userRepository.refreshToken(user.userId);
if (!RTfromRedis) throw new UnauthorizedException('다시 로그인해주세요'); //프론트에서도 없애는 방법을 찾아야함
await this.client.set(`${user.userId}:RT`, RTfromRedis);
}
//2.요청과 다를때
if (refreshToken !== RTfromRedis) {
await this.client.del(`${user.userId}:RT`);
await this.userRepository.removeRefreshToken(user.userId);
//위에 UnauthorizedException으로 해결할수있으면 수정하기
throw new HttpException(
{
status: HttpStatus.UNAUTHORIZED,
error: '로그인이 필요합니다.',
code: '333',//추후 customize 해서 에러 메세지 쓸수있도록
},
HttpStatus.UNAUTHORIZED,
);
}
//3.기간이 확인
await this.tokenExpiration(user.userId, RTfromRedis);
//4.문제 없다면!
return await this.getAccessToken(user);
}
async tokenExpiration(userId: number, refreshToken: string): Promise<void> {
const decodedToken = this.jwtService.verify(refreshToken);
const refreshTokenExp = new Date(decodedToken.exp * 1000);
console.log(refreshTokenExp);
if (refreshTokenExp < new Date()) {
await this.userRepository.removeRefreshToken(userId);
await this.client.del(`${userId}:RT`);
throw new HttpException(
{
status: HttpStatus.UNAUTHORIZED,
error: '로그인이 필요합니다.',
code: '333',//추후 customize 해서 에러 메세지 쓸수있도록
},
HttpStatus.UNAUTHORIZED,
);
}
}