redis 제거
This commit is contained in:
@@ -6,20 +6,15 @@ import { VerificationService } from './verification.service';
|
||||
*
|
||||
* @description
|
||||
* 인증번호 생성 및 검증 기능을 제공하는 모듈입니다.
|
||||
* Redis를 사용하여 인증번호를 임시 저장하고 검증합니다.
|
||||
* 메모리 Map을 사용하여 인증번호를 임시 저장하고 검증합니다.
|
||||
*
|
||||
* 사용 예:
|
||||
* - 아이디 찾기 인증번호 발송
|
||||
* - 비밀번호 재설정 인증번호 발송
|
||||
* - 회원가입 이메일 인증
|
||||
*
|
||||
* RedisModule이 @Global로 설정되어 있어 자동으로 주입됩니다.
|
||||
*
|
||||
* @export
|
||||
* @class VerificationModule
|
||||
*/
|
||||
@Module({
|
||||
providers: [VerificationService],
|
||||
exports: [VerificationService],
|
||||
providers: [VerificationService],
|
||||
exports: [VerificationService],
|
||||
})
|
||||
export class VerificationModule {}
|
||||
|
||||
@@ -1,32 +1,40 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { InjectRedis } from '@nestjs-modules/ioredis';
|
||||
import Redis from 'ioredis';
|
||||
import * as crypto from 'crypto';
|
||||
import { VERIFICATION_CONFIG } from 'src/common/config/VerificationConfig';
|
||||
|
||||
/**
|
||||
* 인증번호 생성 및 검증 서비스 (Redis 기반)
|
||||
* 인증번호 생성 및 검증 서비스 (메모리 기반)
|
||||
*/
|
||||
@Injectable()
|
||||
export class VerificationService {
|
||||
private readonly logger = new Logger(VerificationService.name);
|
||||
|
||||
// 메모리 저장소 (key -> { code, expiresAt })
|
||||
private readonly store = new Map<string, { value: string; expiresAt: number }>();
|
||||
|
||||
constructor(@InjectRedis() private readonly redis: Redis) {
|
||||
this.logger.log(`[REDIS] VerificationService 초기화`);
|
||||
process.stdout.write(`[REDIS] VerificationService initialized\n`);
|
||||
constructor() {
|
||||
this.logger.log(`[VERIFY] VerificationService 초기화 (메모리 모드)`);
|
||||
|
||||
// Redis 연결 상태 로깅
|
||||
this.checkRedisConnection();
|
||||
// 만료된 항목 정리 (1분마다)
|
||||
setInterval(() => this.cleanup(), 60000);
|
||||
}
|
||||
|
||||
private async checkRedisConnection(): Promise<void> {
|
||||
try {
|
||||
const pong = await this.redis.ping();
|
||||
this.logger.log(`[REDIS] 연결 상태: ${pong}`);
|
||||
process.stdout.write(`[REDIS] Connection status: ${pong}\n`);
|
||||
} catch (error) {
|
||||
this.logger.error(`[REDIS] 연결 실패: ${error.message}`);
|
||||
process.stdout.write(`[REDIS] Connection FAILED: ${error.message}\n`);
|
||||
/**
|
||||
* 만료된 항목 정리
|
||||
*/
|
||||
private cleanup(): void {
|
||||
const now = Date.now();
|
||||
let cleaned = 0;
|
||||
|
||||
for (const [key, data] of this.store.entries()) {
|
||||
if (data.expiresAt < now) {
|
||||
this.store.delete(key);
|
||||
cleaned++;
|
||||
}
|
||||
}
|
||||
|
||||
if (cleaned > 0) {
|
||||
this.logger.debug(`[VERIFY] 만료된 ${cleaned}개 항목 정리됨`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,109 +43,89 @@ export class VerificationService {
|
||||
*/
|
||||
generateCode(): string {
|
||||
const code = Math.floor(100000 + Math.random() * 900000).toString();
|
||||
this.logger.log(`[REDIS] 인증번호 생성: ${code}`);
|
||||
this.logger.log(`[VERIFY] 인증번호 생성: ${code}`);
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 인증번호 저장 (Redis)
|
||||
* 인증번호 저장 (TTL 적용)
|
||||
*/
|
||||
async saveCode(key: string, code: string): Promise<void> {
|
||||
this.logger.log(`[REDIS] ========== 코드 저장 시작 ==========`);
|
||||
this.logger.log(`[REDIS] Key: ${key}`);
|
||||
this.logger.log(`[REDIS] Code: ${code}`);
|
||||
this.logger.log(`[REDIS] TTL: ${VERIFICATION_CONFIG.CODE_EXPIRY_SECONDS}초`);
|
||||
process.stdout.write(`[REDIS] Saving - Key: ${key}, Code: ${code}\n`);
|
||||
|
||||
try {
|
||||
const result = await this.redis.set(key, code, 'EX', VERIFICATION_CONFIG.CODE_EXPIRY_SECONDS);
|
||||
this.logger.log(`[REDIS] 저장 결과: ${result}`);
|
||||
process.stdout.write(`[REDIS] Save result: ${result}\n`);
|
||||
} catch (error) {
|
||||
this.logger.error(`[REDIS] ========== 저장 실패 ==========`);
|
||||
this.logger.error(`[REDIS] Error: ${error.message}`);
|
||||
this.logger.error(`[REDIS] Stack: ${error.stack}`);
|
||||
process.stdout.write(`[REDIS] SAVE ERROR: ${error.message}\n`);
|
||||
process.stdout.write(`[REDIS] STACK: ${error.stack}\n`);
|
||||
throw error;
|
||||
}
|
||||
const expiresAt = Date.now() + (VERIFICATION_CONFIG.CODE_EXPIRY_SECONDS * 1000);
|
||||
|
||||
this.store.set(key, { value: code, expiresAt });
|
||||
|
||||
this.logger.log(`[VERIFY] 코드 저장 - Key: ${key}, TTL: ${VERIFICATION_CONFIG.CODE_EXPIRY_SECONDS}초`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 인증번호 검증
|
||||
*/
|
||||
async verifyCode(key: string, code: string): Promise<boolean> {
|
||||
this.logger.log(`[REDIS] ========== 코드 검증 시작 ==========`);
|
||||
this.logger.log(`[REDIS] Key: ${key}`);
|
||||
this.logger.log(`[REDIS] Input Code: ${code}`);
|
||||
process.stdout.write(`[REDIS] Verifying - Key: ${key}, Input: ${code}\n`);
|
||||
this.logger.log(`[VERIFY] 코드 검증 - Key: ${key}, Input: ${code}`);
|
||||
|
||||
try {
|
||||
const savedCode = await this.redis.get(key);
|
||||
this.logger.log(`[REDIS] Saved Code: ${savedCode}`);
|
||||
process.stdout.write(`[REDIS] Saved code: ${savedCode}\n`);
|
||||
const data = this.store.get(key);
|
||||
|
||||
if (!savedCode) {
|
||||
this.logger.warn(`[REDIS] 저장된 코드 없음 (만료 또는 미발급)`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (savedCode !== code) {
|
||||
this.logger.warn(`[REDIS] 코드 불일치 - Saved: ${savedCode}, Input: ${code}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
await this.redis.del(key);
|
||||
this.logger.log(`[REDIS] 검증 성공, 코드 삭제됨`);
|
||||
return true;
|
||||
|
||||
} catch (error) {
|
||||
this.logger.error(`[REDIS] ========== 검증 실패 ==========`);
|
||||
this.logger.error(`[REDIS] Error: ${error.message}`);
|
||||
this.logger.error(`[REDIS] Stack: ${error.stack}`);
|
||||
process.stdout.write(`[REDIS] VERIFY ERROR: ${error.message}\n`);
|
||||
throw error;
|
||||
if (!data) {
|
||||
this.logger.warn(`[VERIFY] 저장된 코드 없음 (만료 또는 미발급)`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 만료 체크
|
||||
if (data.expiresAt < Date.now()) {
|
||||
this.logger.warn(`[VERIFY] 코드 만료됨`);
|
||||
this.store.delete(key);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data.value !== code) {
|
||||
this.logger.warn(`[VERIFY] 코드 불일치 - Saved: ${data.value}, Input: ${code}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 검증 성공 시 삭제 (1회용)
|
||||
this.store.delete(key);
|
||||
this.logger.log(`[VERIFY] 검증 성공, 코드 삭제됨`);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 비밀번호 재설정 토큰 생성 및 저장
|
||||
*/
|
||||
async generateResetToken(userId: string): Promise<string> {
|
||||
this.logger.log(`[REDIS] 리셋 토큰 생성 - userId: ${userId}`);
|
||||
this.logger.log(`[VERIFY] 리셋 토큰 생성 - userId: ${userId}`);
|
||||
|
||||
try {
|
||||
const token = crypto.randomBytes(VERIFICATION_CONFIG.TOKEN_BYTES_LENGTH).toString('hex');
|
||||
await this.redis.set(`reset:${token}`, userId, 'EX', VERIFICATION_CONFIG.RESET_TOKEN_EXPIRY_SECONDS);
|
||||
this.logger.log(`[REDIS] 리셋 토큰 저장 완료`);
|
||||
return token;
|
||||
} catch (error) {
|
||||
this.logger.error(`[REDIS] 리셋 토큰 생성 실패: ${error.message}`);
|
||||
throw error;
|
||||
}
|
||||
const token = crypto.randomBytes(VERIFICATION_CONFIG.TOKEN_BYTES_LENGTH).toString('hex');
|
||||
const expiresAt = Date.now() + (VERIFICATION_CONFIG.RESET_TOKEN_EXPIRY_SECONDS * 1000);
|
||||
|
||||
this.store.set(`reset:${token}`, { value: userId, expiresAt });
|
||||
|
||||
this.logger.log(`[VERIFY] 리셋 토큰 저장 완료`);
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* 비밀번호 재설정 토큰 검증
|
||||
*/
|
||||
async verifyResetToken(token: string): Promise<string | null> {
|
||||
this.logger.log(`[REDIS] 리셋 토큰 검증`);
|
||||
this.logger.log(`[VERIFY] 리셋 토큰 검증`);
|
||||
|
||||
try {
|
||||
const userId = await this.redis.get(`reset:${token}`);
|
||||
const key = `reset:${token}`;
|
||||
const data = this.store.get(key);
|
||||
|
||||
if (!userId) {
|
||||
this.logger.warn(`[REDIS] 리셋 토큰 없음 또는 만료`);
|
||||
return null;
|
||||
}
|
||||
|
||||
await this.redis.del(`reset:${token}`);
|
||||
this.logger.log(`[REDIS] 리셋 토큰 검증 성공 - userId: ${userId}`);
|
||||
return userId;
|
||||
|
||||
} catch (error) {
|
||||
this.logger.error(`[REDIS] 리셋 토큰 검증 실패: ${error.message}`);
|
||||
throw error;
|
||||
if (!data) {
|
||||
this.logger.warn(`[VERIFY] 리셋 토큰 없음 또는 만료`);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (data.expiresAt < Date.now()) {
|
||||
this.logger.warn(`[VERIFY] 리셋 토큰 만료됨`);
|
||||
this.store.delete(key);
|
||||
return null;
|
||||
}
|
||||
|
||||
this.store.delete(key);
|
||||
this.logger.log(`[VERIFY] 리셋 토큰 검증 성공 - userId: ${data.value}`);
|
||||
return data.value;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user