Skip to content

Commit d8a9b58

Browse files
authored
[#48] refactor: 프론트에 에러 출력 세분화 (#49)
1 parent 4b5c651 commit d8a9b58

File tree

9 files changed

+51
-279
lines changed

9 files changed

+51
-279
lines changed

Diff for: build.gradle

+3-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ sonar {
4141
property "sonar.host.url", "https://sonarcloud.io"
4242
property "sonar.coverage.jacoco.xmlReportPaths", "build/reports/jacoco/test/jacocoTestReport.xml"
4343
property "sonar.exclusions", "**/*Application*.java, **/*Config*.java, **/*GlobalExceptionHandler.java, **/Q*.java, **/DynamicQuery.java, " +
44-
"**/*Exception.java, **/*Adapter.java, **/CustomOAuth2UserService.java, **/*SearchRepository.java"
44+
"**/*Exception.java, **/*Adapter.java, **/CustomOAuth2UserService.java, **/*SearchRepository.java, **/*Filter.java"
4545
property "sonar.java.coveragePlugin", "jacoco"
4646
}
4747
}
@@ -123,7 +123,8 @@ jacocoTestCoverageVerification {
123123
'*.Q*',
124124
'*.DynamicQuery',
125125
'*.*Adapter',
126-
'*.*SearchRepository'
126+
'*.*SearchRepository',
127+
'*.*.CustomUserDetails'
127128
]
128129
}
129130
}

Diff for: src/main/java/com/tnt/common/error/handler/GlobalExceptionHandler.java

+2-19
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@
33
import static com.tnt.common.error.model.ErrorMessage.INPUT_VALUE_IS_INVALID;
44
import static com.tnt.common.error.model.ErrorMessage.MISSING_REQUIRED_PARAMETER_ERROR;
55
import static com.tnt.common.error.model.ErrorMessage.PARAMETER_FORMAT_NOT_CORRECT;
6-
import static com.tnt.common.error.model.ErrorMessage.SERVER_ERROR;
76
import static org.springframework.http.HttpStatus.BAD_REQUEST;
87
import static org.springframework.http.HttpStatus.CONFLICT;
98
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
109
import static org.springframework.http.HttpStatus.NOT_FOUND;
1110
import static org.springframework.http.HttpStatus.UNAUTHORIZED;
1211

13-
import java.security.SecureRandom;
1412
import java.time.DateTimeException;
1513
import java.util.List;
1614

@@ -37,12 +35,6 @@
3735
@RestControllerAdvice
3836
public class GlobalExceptionHandler {
3937

40-
private static final String ERROR_KEY_FORMAT = "%n error key : %s";
41-
private static final String CHARACTERS = "abcdefghijklmnopqrstuvwxyz";
42-
private static final int ERROR_KEY_LENGTH = 5;
43-
private static final String EXCEPTION_CLASS_TYPE_MESSAGE_FORMANT = "%n class type : %s";
44-
private final SecureRandom secureRandom = new SecureRandom();
45-
4638
// 필수 파라미터 예외
4739
@ResponseStatus(BAD_REQUEST)
4840
@ExceptionHandler(MissingServletRequestParameterException.class)
@@ -154,17 +146,8 @@ protected ErrorResponse handleIllegalArgumentException(IllegalArgumentException
154146
@ResponseStatus(INTERNAL_SERVER_ERROR)
155147
@ExceptionHandler(RuntimeException.class)
156148
protected ErrorResponse handleRuntimeException(RuntimeException exception) {
157-
StringBuilder sb = new StringBuilder();
158-
159-
for (int i = 0; i < ERROR_KEY_LENGTH; i++) {
160-
sb.append(CHARACTERS.charAt(secureRandom.nextInt(CHARACTERS.length())));
161-
}
162-
163-
String errorKeyInfo = String.format(ERROR_KEY_FORMAT, sb);
164-
String exceptionTypeInfo = String.format(EXCEPTION_CLASS_TYPE_MESSAGE_FORMANT, exception.getClass());
165-
166-
log.error("{} {} {}", exception.getMessage(), errorKeyInfo, exceptionTypeInfo, exception);
149+
log.error(exception.getMessage(), exception);
167150

168-
return new ErrorResponse(SERVER_ERROR + errorKeyInfo);
151+
return new ErrorResponse(exception.getMessage());
169152
}
170153
}

Diff for: src/main/java/com/tnt/gateway/config/SecurityConfig.java

+14-20
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.tnt.gateway.config;
22

3+
import static jakarta.servlet.http.HttpServletResponse.SC_NOT_FOUND;
4+
35
import java.util.Arrays;
46

57
import org.springframework.context.annotation.Bean;
@@ -14,12 +16,11 @@
1416
import org.springframework.security.web.SecurityFilterChain;
1517
import org.springframework.security.web.authentication.logout.LogoutFilter;
1618

17-
import com.tnt.gateway.filter.ServletExceptionFilter;
19+
import com.fasterxml.jackson.databind.ObjectMapper;
20+
import com.tnt.common.error.model.ErrorResponse;
1821
import com.tnt.gateway.filter.SessionAuthenticationFilter;
19-
import com.tnt.gateway.service.CustomOAuth2UserService;
2022
import com.tnt.gateway.service.SessionService;
2123

22-
import jakarta.servlet.http.HttpServletResponse;
2324
import lombok.RequiredArgsConstructor;
2425
import lombok.extern.slf4j.Slf4j;
2526

@@ -40,7 +41,7 @@ public class SecurityConfig {
4041
"/members/sign-up"
4142
};
4243

43-
private final CustomOAuth2UserService customOAuth2UserService;
44+
private final ObjectMapper objectMapper;
4445
private final SessionService sessionService;
4546

4647
@Bean
@@ -54,30 +55,23 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
5455
.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin))
5556
.sessionManagement(sessionManagement ->
5657
sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
57-
.oauth2Login(oauth2 -> oauth2.userInfoEndpoint(userInfo -> userInfo.userService(customOAuth2UserService)))
5858
.authorizeHttpRequests(request -> request
5959
.requestMatchers(ALLOWED_URIS).permitAll().anyRequest().authenticated())
60-
.addFilterBefore(servletExceptionFilter(), LogoutFilter.class)
6160
.addFilterAfter(sessionAuthenticationFilter(), LogoutFilter.class)
62-
.exceptionHandling(exceptionHandling ->
63-
exceptionHandling.authenticationEntryPoint((request, response, authException) -> {
64-
log.error("SecurityFilter Exception.", authException);
65-
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
66-
response.setContentType("application/json;charset=UTF-8");
67-
response.getWriter().write("{\"message\":\"Security 사용자 인증에 실패했습니다.\"}");
68-
})
69-
);
61+
.exceptionHandling(e -> e.authenticationEntryPoint((request, response, authException) -> {
62+
log.error("(Invalid URL) Security Filter Error: {}", authException.getMessage(), authException);
7063

71-
return http.build();
72-
}
64+
response.setStatus(SC_NOT_FOUND);
65+
response.setContentType("application/json;charset=UTF-8");
66+
response.getWriter()
67+
.write(objectMapper.writeValueAsString(new ErrorResponse("Invalid URL")));
68+
}));
7369

74-
@Bean
75-
public ServletExceptionFilter servletExceptionFilter() {
76-
return new ServletExceptionFilter();
70+
return http.build();
7771
}
7872

7973
@Bean
8074
public SessionAuthenticationFilter sessionAuthenticationFilter() {
81-
return new SessionAuthenticationFilter(Arrays.asList(ALLOWED_URIS), sessionService);
75+
return new SessionAuthenticationFilter(Arrays.asList(ALLOWED_URIS), sessionService, objectMapper);
8276
}
8377
}

Diff for: src/main/java/com/tnt/gateway/filter/ServletExceptionFilter.java

-53
This file was deleted.

Diff for: src/main/java/com/tnt/gateway/filter/SessionAuthenticationFilter.java

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.tnt.gateway.filter;
22

3+
import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
4+
35
import java.io.IOException;
46
import java.util.List;
57

@@ -12,6 +14,9 @@
1214
import org.springframework.util.AntPathMatcher;
1315
import org.springframework.web.filter.OncePerRequestFilter;
1416

17+
import com.fasterxml.jackson.databind.ObjectMapper;
18+
import com.tnt.common.error.exception.UnauthorizedException;
19+
import com.tnt.common.error.model.ErrorResponse;
1520
import com.tnt.gateway.service.SessionService;
1621

1722
import jakarta.servlet.FilterChain;
@@ -25,10 +30,13 @@
2530
@RequiredArgsConstructor
2631
public class SessionAuthenticationFilter extends OncePerRequestFilter {
2732

33+
private static final String AUTHORIZATION_HEADER = "Authorization";
34+
2835
private final GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
2936
private final AntPathMatcher pathMatcher = new AntPathMatcher();
3037
private final List<String> allowedUris;
3138
private final SessionService sessionService;
39+
private final ObjectMapper objectMapper;
3240

3341
@Override
3442
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
@@ -44,7 +52,16 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
4452
return;
4553
}
4654

47-
saveAuthentication(sessionService.authenticate(request));
55+
try {
56+
saveAuthentication(sessionService.authenticate(request.getHeader(AUTHORIZATION_HEADER)));
57+
} catch (UnauthorizedException e) {
58+
response.setContentType("application/json;charset=UTF-8");
59+
response.setStatus(SC_BAD_REQUEST);
60+
response.getWriter().write(objectMapper.writeValueAsString(new ErrorResponse(e.getMessage())));
61+
62+
return;
63+
}
64+
4865
filterChain.doFilter(request, response);
4966
}
5067

Diff for: src/main/java/com/tnt/gateway/service/SessionService.java

+1-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
import com.tnt.common.error.exception.UnauthorizedException;
1414

15-
import jakarta.servlet.http.HttpServletRequest;
1615
import lombok.RequiredArgsConstructor;
1716
import lombok.extern.slf4j.Slf4j;
1817

@@ -22,13 +21,11 @@
2221
public class SessionService {
2322

2423
private static final long SESSION_DURATION = 7L * 24 * 60 * 60; // 24시간 * 7일
25-
private static final String AUTHORIZATION_HEADER = "Authorization";
2624
private static final String SESSION_ID_PREFIX = "SESSION-ID ";
2725

2826
private final StringRedisTemplate redisTemplate;
2927

30-
public String authenticate(HttpServletRequest request) {
31-
String authHeader = request.getHeader(AUTHORIZATION_HEADER);
28+
public String authenticate(String authHeader) {
3229

3330
if (isBlank(authHeader) || !authHeader.startsWith(SESSION_ID_PREFIX)) {
3431
log.error("Authorization Header Error: [{}]", authHeader);

Diff for: src/test/java/com/tnt/gateway/filter/ServletExceptionFilterTest.java

-124
This file was deleted.

0 commit comments

Comments
 (0)