Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ dependencies {
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'

// Redis 체크
implementation 'io.lettuce:lettuce-core'

// AOP
implementation 'org.springframework.boot:spring-boot-starter-aop'


}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import DiffLens.back_end.domain.members.dto.auth.AuthRequestDTO;
import DiffLens.back_end.domain.members.dto.auth.AuthResponseDTO;
import DiffLens.back_end.domain.members.service.AuthService;
import DiffLens.back_end.domain.members.service.auth.AuthService;
import DiffLens.back_end.global.responses.exception.ApiResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package DiffLens.back_end.domain.members.service;
package DiffLens.back_end.domain.members.service.auth;

import DiffLens.back_end.domain.members.auth.StrategyFactory;
import DiffLens.back_end.domain.members.auth.strategy.interfaces.AuthStrategy;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package DiffLens.back_end.domain.members.service.auth;

import DiffLens.back_end.domain.members.entity.Member;
import DiffLens.back_end.global.responses.code.status.error.AuthStatus;
import DiffLens.back_end.global.responses.exception.handler.ErrorHandler;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

@Service
public class CurrentUserService {

public Member getCurrentUser() {
var authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
throw new ErrorHandler(AuthStatus.AUTHENTICATION_FAILED);
}

var principal = authentication.getPrincipal();
if (principal == null) {
throw new ErrorHandler(AuthStatus.AUTHENTICATION_FAILED);
}

if (!(principal instanceof Member)) {
throw new ErrorHandler(AuthStatus.AUTHENTICATION_FAILED);
}

return (Member) principal;
}

public Long getCurrentUserId() {
Member user = getCurrentUser();
return user != null ? user.getId() : null;
}

public String getCurrentUserEmail() {
Member user = getCurrentUser();
return user != null ? user.getEmail() : null;
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package DiffLens.back_end.global.aop;

import DiffLens.back_end.domain.members.service.auth.CurrentUserService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class ApiRequestLogAspect {

private final CurrentUserService authService;

/**
* 전/후 처리 모두 가능
* CommonPointcut.restControllerEndpoints() Pointcut 지정하여
* API 호출 시 호출 전후로 로그 출력하도록 하는 Aspect
*/
@Around("CommonPointCut.restControllerEndpoints()")
public Object logApiRequest(ProceedingJoinPoint jp) throws Throwable {
long start = System.currentTimeMillis();

ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = attrs.getRequest();
String uri = request.getRequestURI();
String httpMethod = request.getMethod();

Object currentUser = null;
try { currentUser = authService.getCurrentUser(); } catch (Exception ignored) {}

String methodName = jp.getSignature().getName();
String args = jp.getArgs() != null ? String.join(", ", java.util.Arrays.stream(jp.getArgs())
.map(String::valueOf).toArray(String[]::new)) : "";

String userInfo = currentUser != null ? "[User: " + currentUser + "]" : "[User: Anonymous]";
String requestInfo = "[" + httpMethod + ": " + uri + " - " + methodName + "(" + args + ")]";

log.info("⏳ [API 호출 시작] {} {}", userInfo, requestInfo);

try {
Object result = jp.proceed();
long end = System.currentTimeMillis();
log.info("✅ [API 호출 종료] {} {} - 실행시간: {}ms", userInfo, requestInfo, (end - start));
return result;
} catch (Throwable ex) {
long end = System.currentTimeMillis();
log.error("❌ [API 호출 예외] {} {} - 실행시간: {}ms - 예외: {}", userInfo, requestInfo, (end - start), ex.getMessage());
throw ex; // 예외를 다시 던져서 컨트롤러에게 전달
}
}

}
10 changes: 10 additions & 0 deletions src/main/java/DiffLens/back_end/global/aop/CommonPointCut.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package DiffLens.back_end.global.aop;

import org.aspectj.lang.annotation.Pointcut;

public class CommonPointCut {

// API 호출 시 로그 찍도록 @RestController 어노테이션에 PointCut 설정
@Pointcut("within(@org.springframework.web.bind.annotation.RestController *)")
public void restControllerEndpoints() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package DiffLens.back_end.global.redis;

import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

@Slf4j
@Component
@RequiredArgsConstructor
public class RedisHealthChecker {

private final RedisTemplate<String, Object> redisTemplate;

@PostConstruct
public void checkRedisConnection() {
log.info("[Connection Check] Redis 연결 체크...");
try {
String ping = redisTemplate.getConnectionFactory() != null ? redisTemplate.getConnectionFactory()
.getConnection()
.ping() : "null";
if(!"PONG".equals(ping)) {
log.error("[Connection Check] Redis 연결 실패 ❌ - 응답값이 'PONG' 이 아님");
throw new IllegalStateException("Redis 연결 실패: PING 응답 이상. 응답=" + ping);
}
}catch (Exception e) {
log.error("[Connection Check] Redis 연결 실패 ❌ - {}", e.getMessage());
throw new IllegalStateException("Redis 연결 실패: " + e.getMessage(), e);
}
log.info("[Connection Check] Redis 연결 성공 ✅");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
@AllArgsConstructor
public enum AuthStatus implements BaseErrorCode {

AUTHENTICATION_FAILED(HttpStatus.UNAUTHORIZED, "AUTH400", "인증에 실패했습니다."),

USER_NOT_FOUND(HttpStatus.NOT_FOUND, "AUTH401", "존재하지 않는 사용자입니다."),
ALREADY_EXISTS(HttpStatus.BAD_REQUEST, "AUTH402", "이미 존재하는 사용자입니다."),
INVALID_PASSWORD(HttpStatus.BAD_REQUEST, "AUTH403", "올바르지 않은 비밀번호입니다."),
Expand All @@ -22,7 +24,7 @@ public enum AuthStatus implements BaseErrorCode {

SOCIAL_USERINFO_API_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "AUTH504", "소셜 사용자 정보를 가져오지 못했습니다."),
SOCIAL_USERINFO_NETWORK_ERROR(HttpStatus.SERVICE_UNAVAILABLE, "AUTH505", "소셜 사용자 정보 요청 중 네트워크 오류가 발생했습니다."),
SOCIAL_USERINFO_UNKNOWN_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "AUTH506", "소셜 사용자 정보 처리 중 오류가 발생했습니다.")
SOCIAL_USERINFO_UNKNOWN_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "AUTH506", "소셜 사용자 정보 처리 중 오류가 발생했습니다."),

;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public ResponseEntity<Object> handleMethodArgumentNotValid(
});

return handleExceptionInternalArgs(
e, HttpHeaders.EMPTY, ErrorStatus.valueOf("_BAD_REQUEST"), request, errors);
e, HttpHeaders.EMPTY, ErrorStatus.valueOf("BAD_REQUEST"), request, errors);
}

@ExceptionHandler
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/application-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ spring:
redis:
host: ${REDIS_HOSTNAME}
port: ${REDIS_PORT}
timeout: 2000ms



Expand Down
1 change: 1 addition & 0 deletions src/main/resources/application-local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ spring:
redis:
host: localhost
port: 6381
timeout: 2000ms



Expand Down
Loading