로그인 기능 추가

This commit is contained in:
2025-12-04 16:51:24 +09:00
parent a7d03a0086
commit f41e82e3ca
10 changed files with 335 additions and 307 deletions

View File

@@ -35,7 +35,6 @@ public class ApiLogFunction {
// 사용자 ID 추출 예시 (Spring Security 기준)
public static String getUserId(HttpServletRequest request) {
try {
Object userId = request.getUserPrincipal();
return request.getUserPrincipal() != null ? request.getUserPrincipal().getName() : null;
} catch (Exception e) {
return null;
@@ -65,22 +64,22 @@ public class ApiLogFunction {
}
public static String getRequestBody(
HttpServletRequest servletRequest, ContentCachingRequestWrapper contentWrapper) {
HttpServletRequest servletRequest, ContentCachingRequestWrapper contentWrapper) {
StringBuilder resultBody = new StringBuilder();
// GET, form-urlencoded POST 파라미터
Map<String, String[]> paramMap = servletRequest.getParameterMap();
String queryParams =
paramMap.entrySet().stream()
.map(e -> e.getKey() + "=" + String.join(",", e.getValue()))
.collect(Collectors.joining("&"));
paramMap.entrySet().stream()
.map(e -> e.getKey() + "=" + String.join(",", e.getValue()))
.collect(Collectors.joining("&"));
resultBody.append(queryParams.isEmpty() ? "" : queryParams);
// JSON Body
if ("POST".equalsIgnoreCase(servletRequest.getMethod())
&& servletRequest.getContentType() != null
&& servletRequest.getContentType().contains("application/json")) {
&& servletRequest.getContentType() != null
&& servletRequest.getContentType().contains("application/json")) {
try {
// json인 경우는 Wrapper를 통해 가져오기
resultBody.append(getBodyData(contentWrapper));
@@ -92,8 +91,8 @@ public class ApiLogFunction {
// Multipart form-data
if ("POST".equalsIgnoreCase(servletRequest.getMethod())
&& servletRequest.getContentType() != null
&& servletRequest.getContentType().startsWith("multipart/form-data")) {
&& servletRequest.getContentType() != null
&& servletRequest.getContentType().startsWith("multipart/form-data")) {
resultBody.append("multipart/form-data request");
}

View File

@@ -1,15 +1,16 @@
package com.kamco.cd.kamcoback.config.api;
import com.kamco.cd.kamcoback.auth.CustomUserDetails;
import com.kamco.cd.kamcoback.postgres.entity.AuditLogEntity;
import com.kamco.cd.kamcoback.postgres.repository.log.AuditLogRepository;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Optional;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import org.springframework.web.util.ContentCachingRequestWrapper;
@@ -30,19 +31,19 @@ public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(
MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
// ApiResponseDto를 반환하는 경우에만 적용
return returnType.getParameterType().equals(ApiResponseDto.class);
}
@Override
public Object beforeBodyWrite(
Object body,
MethodParameter returnType,
MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request,
ServerHttpResponse response) {
Object body,
MethodParameter returnType,
MediaType selectedContentType,
Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request,
ServerHttpResponse response) {
HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest();
ContentCachingRequestWrapper contentWrapper = (ContentCachingRequestWrapper) servletRequest;
@@ -52,21 +53,34 @@ public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {
response.setStatusCode(apiResponse.getHttpStatus());
String ip = ApiLogFunction.getClientIp(servletRequest);
// TODO : userid 가 계정명인지, uid 인지 확인 후 로직 수정 필요함
Long userid =
Long.valueOf(Optional.ofNullable(ApiLogFunction.getUserId(servletRequest)).orElse("1"));
Long userid = null;
/**
* servletRequest.getUserPrincipal() instanceof UsernamePasswordAuthenticationToken auth
* 이 요청이 JWT 인증을 통과한 요청인가? 그리고 Spring Security Authentication 객체가 UsernamePasswordAuthenticationToken 타입인가? 체크
*/
/**
* auth.getPrincipal() instanceof CustomUserDetails customUserDetails
* principal 안에 들어있는 객체가 내가 만든 CustomUserDetails 타입인가? 체크
*/
if (servletRequest.getUserPrincipal() instanceof UsernamePasswordAuthenticationToken auth
&& auth.getPrincipal() instanceof CustomUserDetails customUserDetails) {
// audit 에는 long 타입 user_id가 들어가지만 토큰 sub은 uuid여서 user_id 가져오기
userid = customUserDetails.getMember().getId();
}
// TODO: menuUid 를 동적으로 가져오게끔 해야함
AuditLogEntity log =
new AuditLogEntity(
userid,
ApiLogFunction.getEventType(servletRequest),
ApiLogFunction.isSuccessFail(apiResponse),
"MU_01_01",
ip,
servletRequest.getRequestURI(),
ApiLogFunction.getRequestBody(servletRequest, contentWrapper),
apiResponse.getErrorLogUid());
new AuditLogEntity(
userid,
ApiLogFunction.getEventType(servletRequest),
ApiLogFunction.isSuccessFail(apiResponse),
"MU_01_01",
ip,
servletRequest.getRequestURI(),
ApiLogFunction.getRequestBody(servletRequest, contentWrapper),
apiResponse.getErrorLogUid());
// tb_audit_log 테이블 저장
auditLogRepository.save(log);