Merge remote-tracking branch 'origin/feat/dev_251201' into feat/dev_251201

This commit is contained in:
DanielLee
2025-12-08 11:21:23 +09:00
3 changed files with 53 additions and 18 deletions

View File

@@ -70,6 +70,10 @@ public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {
// audit 에는 long 타입 user_id가 들어가지만 토큰 sub은 uuid여서 user_id 가져오기
userid = customUserDetails.getMember().getId();
}
String requestBody = ApiLogFunction.getRequestBody(servletRequest, contentWrapper);
requestBody = maskSensitiveFields(requestBody); // 로그 저장전에 중요정보 마스킹
// TODO: menuUid 를 동적으로 가져오게끔 해야함
AuditLogEntity log =
new AuditLogEntity(
@@ -79,13 +83,33 @@ public class ApiResponseAdvice implements ResponseBodyAdvice<Object> {
"MU_01_01",
ip,
servletRequest.getRequestURI(),
ApiLogFunction.getRequestBody(servletRequest, contentWrapper),
requestBody,
apiResponse.getErrorLogUid());
// tb_audit_log 테이블 저장
auditLogRepository.save(log);
}
return body;
}
/**
* 마스킹
*
* @param json
* @return
*/
private String maskSensitiveFields(String json) {
if (json == null) {
return null;
}
// password 마스킹
json = json.replaceAll("\"password\"\\s*:\\s*\"[^\"]*\"", "\"password\":\"****\"");
// 토큰 마스킹
json = json.replaceAll("\"accessToken\"\\s*:\\s*\"[^\"]*\"", "\"accessToken\":\"****\"");
json = json.replaceAll("\"refreshToken\"\\s*:\\s*\"[^\"]*\"", "\"refreshToken\":\"****\"");
return json;
}
}

View File

@@ -2,6 +2,8 @@ package com.kamco.cd.kamcoback.members;
import com.kamco.cd.kamcoback.auth.JwtTokenProvider;
import com.kamco.cd.kamcoback.auth.RefreshTokenService;
import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.members.dto.SignInRequest;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -9,6 +11,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import java.nio.file.AccessDeniedException;
import java.time.Duration;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
@@ -52,7 +55,7 @@ public class AuthController {
description = "ID 또는 비밀번호 불일치",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
public ResponseEntity<TokenResponse> signin(
public ApiResponseDto<TokenResponse> signin(
@io.swagger.v3.oas.annotations.parameters.RequestBody(
description = "로그인 요청 정보",
required = true)
@@ -61,7 +64,7 @@ public class AuthController {
HttpServletResponse response) {
Authentication authentication =
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(request.username(), request.password()));
new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword()));
String username = authentication.getName(); // UserDetailsService 에서 사용한 username
@@ -83,8 +86,7 @@ public class AuthController {
.build();
response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString());
return ResponseEntity.ok(new TokenResponse(accessToken));
return ApiResponseDto.createOK(new TokenResponse(accessToken));
}
@PostMapping("/refresh")
@@ -99,16 +101,16 @@ public class AuthController {
description = "만료되었거나 유효하지 않은 리프레시 토큰",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
public ResponseEntity<TokenResponse> refresh(String refreshToken, HttpServletResponse response) {
public ResponseEntity<TokenResponse> refresh(String refreshToken, HttpServletResponse response) throws AccessDeniedException {
if (refreshToken == null || !jwtTokenProvider.isValidToken(refreshToken)) {
return ResponseEntity.status(401).build();
throw new AccessDeniedException("만료되었거나 유효하지 않은 리프레시 토큰 입니다.");
}
String username = jwtTokenProvider.getSubject(refreshToken);
// Redis에 저장된 RefreshToken과 일치하는지 확인
if (!refreshTokenService.validate(username, refreshToken)) {
return ResponseEntity.status(401).build();
throw new AccessDeniedException("만료되었거나 유효하지 않은 리프레시 토큰 입니다.");
}
// 새 토큰 발급
@@ -141,7 +143,7 @@ public class AuthController {
description = "로그아웃 성공",
content = @Content(schema = @Schema(implementation = Void.class)))
})
public ResponseEntity<Void> logout(Authentication authentication, HttpServletResponse response) {
public ApiResponseDto<ResponseEntity<Object>> logout(Authentication authentication, HttpServletResponse response) {
if (authentication != null) {
String username = authentication.getName();
// Redis에서 RefreshToken 삭제
@@ -159,14 +161,7 @@ public class AuthController {
.build();
response.addHeader(HttpHeaders.SET_COOKIE, cookie.toString());
return ResponseEntity.noContent().build();
}
@Schema(description = "로그인 요청 DTO")
public record SignInRequest(
@Schema(description = "사번", example = "11111") String username,
@Schema(description = "비밀번호", example = "kamco1234!") String password) {
return ApiResponseDto.createOK(ResponseEntity.noContent().build());
}
public record TokenResponse(String accessToken) {

View File

@@ -0,0 +1,16 @@
package com.kamco.cd.kamcoback.members.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString(exclude = "password")
public class SignInRequest {
private String username;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private String password;
}