diff --git a/BE/src/app.module.ts b/BE/src/app.module.ts index 6d13f6c..ef0ed7a 100644 --- a/BE/src/app.module.ts +++ b/BE/src/app.module.ts @@ -30,6 +30,7 @@ import { RedisConfigProvider } from './config/redis.config'; useClass: MysqlConfigProvider, }), CacheModule.registerAsync({ + isGlobal: true, useClass: RedisConfigProvider, }), PostsBlockModule, diff --git a/BE/src/config/redis.config.ts b/BE/src/config/redis.config.ts index 5a05089..fd6ad29 100644 --- a/BE/src/config/redis.config.ts +++ b/BE/src/config/redis.config.ts @@ -8,6 +8,7 @@ export class RedisConfigProvider implements CacheOptionsFactory { store: redisStore, host: this.configService.get('REDIS_HOST'), port: this.configService.get('REDIS_PORT'), + password: this.configService.get('REDIS_PASSWORD'), }; } } diff --git a/BE/src/login/login.controller.ts b/BE/src/login/login.controller.ts index 5e70f42..069a830 100644 --- a/BE/src/login/login.controller.ts +++ b/BE/src/login/login.controller.ts @@ -46,8 +46,9 @@ export class LoginController { checkAccessToken() {} @Post('logout') - logout(@Headers('Authorization') token, @UserHash() userId) { + @UseGuards(AuthGuard) + async logout(@Headers('Authorization') token) { const accessToken = token.split(' ')[1]; - this.loginService.logout(userId, accessToken); + await this.loginService.logout(accessToken); } } diff --git a/BE/src/login/login.service.ts b/BE/src/login/login.service.ts index ced4a99..f7dfbfa 100644 --- a/BE/src/login/login.service.ts +++ b/BE/src/login/login.service.ts @@ -1,4 +1,4 @@ -import { Injectable, Logger } from '@nestjs/common'; +import { Inject, Injectable, Logger } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { InjectRepository } from '@nestjs/typeorm'; import { UserEntity } from '../entities/user.entity'; @@ -9,6 +9,7 @@ import { AppleLoginDto } from './dto/appleLogin.dto'; import * as jwt from 'jsonwebtoken'; import * as jwksClient from 'jwks-rsa'; import { FcmHandler } from '../utils/fcmHandler'; +import { CACHE_MANAGER, CacheStore } from '@nestjs/cache-manager'; export interface SocialProperties { OAuthDomain: string; @@ -30,6 +31,7 @@ export class LoginService { private configService: ConfigService, private jwtService: JwtService, private fcmHandler: FcmHandler, + @Inject(CACHE_MANAGER) private cacheManager: CacheStore, ) { this.jwksClient = jwksClient({ jwksUri: 'https://appleid.apple.com/auth/keys', @@ -45,8 +47,13 @@ export class LoginService { return { access_token: accessToken, refresh_token: refreshToken }; } - async logout(userId, accessToken) { - await this.fcmHandler.removeRegistrationToken(userId); + async logout(accessToken) { + const decodedToken: any = jwt.decode(accessToken); + if (decodedToken && decodedToken.exp) { + await this.fcmHandler.removeRegistrationToken(decodedToken.userId); + const ttl: number = decodedToken.exp - Math.floor(Date.now() / 1000); + await this.cacheManager.set(accessToken, 'logout', { ttl }); + } } async registerUser(socialProperties: SocialProperties) { const userEntity = new UserEntity(); diff --git a/BE/src/utils/auth.guard.ts b/BE/src/utils/auth.guard.ts index 922dedf..4523506 100644 --- a/BE/src/utils/auth.guard.ts +++ b/BE/src/utils/auth.guard.ts @@ -2,24 +2,32 @@ import { CanActivate, ExecutionContext, HttpException, + Inject, Injectable, } from '@nestjs/common'; import * as jwt from 'jsonwebtoken'; +import { CACHE_MANAGER } from '@nestjs/cache-manager'; +import { Cache } from 'cache-manager'; @Injectable() export class AuthGuard implements CanActivate { - canActivate(context: ExecutionContext): boolean { + constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {} + async canActivate(context: ExecutionContext): Promise { const authorizationHeader = context.switchToHttp().getRequest() .headers.authorization; if (!authorizationHeader) throw new HttpException('토큰이 없습니다.', 401); - else { - try { - jwt.verify(authorizationHeader.split(' ')[1], process.env.JWT_SECRET); - return true; - } catch (err) { - return false; - } + + const accessToken = authorizationHeader.split(' ')[1]; + const isBlackList = await this.cacheManager.get(accessToken); + if (isBlackList) { + throw new HttpException('로그아웃된 토큰입니다.', 401); + } + try { + jwt.verify(accessToken, process.env.JWT_SECRET); + return true; + } catch (err) { + return false; } } }