Skip to content

Commit fdc5bff

Browse files
authored
Merge pull request #610 from JNU-econovation/feat/#603
[BE/FEAT] 스웨거 비밀번호 설정
2 parents e13a899 + 9051323 commit fdc5bff

File tree

7 files changed

+140
-11
lines changed

7 files changed

+140
-11
lines changed

src/main/java/com/gaebaljip/exceed/common/EatCeedStaticMessage.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,14 @@ public class EatCeedStaticMessage {
55
public static final String REDIS_REFRESH_TOKEN_KEY = "refresh_";
66

77
public static final String REFRESH_TOKEN = "refreshToken";
8+
public static final String[] SwaggerPatterns = {
9+
"/swagger-resources/**",
10+
"/swagger-ui/**",
11+
"/swagger-ui.html",
12+
"/v3/api-docs/**",
13+
"/v3/api-docs",
14+
"/api-docs/**",
15+
"/api-docs",
16+
"/docs/api-doc.html"
17+
};
818
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.gaebaljip.exceed.common.helper;
2+
3+
import java.util.Arrays;
4+
import java.util.List;
5+
6+
import org.apache.commons.collections.CollectionUtils;
7+
import org.springframework.core.env.Environment;
8+
import org.springframework.stereotype.Component;
9+
10+
import lombok.RequiredArgsConstructor;
11+
12+
@Component
13+
@RequiredArgsConstructor
14+
public class SpringEnvironmentHelper {
15+
16+
private final Environment environment;
17+
18+
private final String PROD = "prod";
19+
private final String STAGING = "staging";
20+
private final String DEV = "dev";
21+
private final List<String> PROD_AND_STAGING = List.of("staging", "prod");
22+
23+
public Boolean isProdProfile() {
24+
String[] activeProfiles = environment.getActiveProfiles();
25+
List<String> currentProfile = Arrays.stream(activeProfiles).toList();
26+
return currentProfile.contains(PROD);
27+
}
28+
29+
public Boolean isStagingProfile() {
30+
String[] activeProfiles = environment.getActiveProfiles();
31+
List<String> currentProfile = Arrays.stream(activeProfiles).toList();
32+
return currentProfile.contains(STAGING);
33+
}
34+
35+
public Boolean isDevProfile() {
36+
String[] activeProfiles = environment.getActiveProfiles();
37+
List<String> currentProfile = Arrays.stream(activeProfiles).toList();
38+
return currentProfile.contains(DEV);
39+
}
40+
41+
public Boolean isProdAndStagingProfile() {
42+
String[] activeProfiles = environment.getActiveProfiles();
43+
List<String> currentProfile = Arrays.stream(activeProfiles).toList();
44+
return CollectionUtils.containsAny(PROD_AND_STAGING, currentProfile);
45+
}
46+
}

src/main/java/com/gaebaljip/exceed/common/security/config/SecurityConfig.java

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
1212
import org.springframework.web.cors.CorsUtils;
1313

14+
import com.gaebaljip.exceed.common.helper.SpringEnvironmentHelper;
1415
import com.gaebaljip.exceed.common.security.domain.JwtManager;
1516
import com.gaebaljip.exceed.common.security.domain.JwtResolver;
1617
import com.gaebaljip.exceed.common.security.exception.JwtAccessDeniedHandler;
@@ -29,6 +30,7 @@ public class SecurityConfig {
2930
private final MemberDetailService memberDetailService;
3031
private final JwtAuthenticationPoint jwtAuthenticationPoint;
3132
private final JwtAccessDeniedHandler jwtAccessDeniedHandler;
33+
private final SpringEnvironmentHelper springEnvironmentHelper;
3234

3335
@Bean
3436
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
@@ -77,12 +79,22 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
7779
.permitAll()
7880
.antMatchers(HttpMethod.POST, "/v1/auth/login", "/v1/auth/refresh")
7981
.permitAll()
82+
.antMatchers(
83+
"/swagger-resources/**",
84+
"/swagger-ui/**",
85+
"/swagger-ui.html",
86+
"/v3/api-docs/**",
87+
"/v3/api-docs",
88+
"/api-docs/**",
89+
"/api-docs")
90+
.permitAll()
8091
.anyRequest()
8192
.authenticated();
8293

8394
// jwt filter 설정
8495
http.addFilterBefore(
85-
new JwtAuthenticationFilter(jwtManager, jwtResolver, memberDetailService),
96+
new JwtAuthenticationFilter(
97+
jwtManager, jwtResolver, memberDetailService, springEnvironmentHelper),
8698
UsernamePasswordAuthenticationFilter.class);
8799
return http.build();
88100
}
@@ -91,16 +103,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
91103
public WebSecurityCustomizer webSecurityCustomizer() {
92104
return (web) ->
93105
web.ignoring()
94-
.antMatchers("/docs/api-doc.html")
95106
.antMatchers("/favicon.*", "/*/icon-*")
96-
.antMatchers(
97-
"/swagger-resources/**",
98-
"/swagger-ui/**",
99-
"/swagger-ui.html",
100-
"/v3/api-docs/**",
101-
"/v3/api-docs",
102-
"/api-docs/**",
103-
"/api-docs")
104107
.requestMatchers(PathRequest.toStaticResources().atCommonLocations());
105108
}
106109
}

src/main/java/com/gaebaljip/exceed/common/security/exception/JwtAuthenticationPoint.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,14 @@ public void commence(
3636
HttpServletResponse response,
3737
AuthenticationException authException)
3838
throws IOException {
39-
if (request.getAttribute("exception") == null) {
39+
40+
if (request.getAttribute("swaggerCannotProdException") != null) {
41+
resolver.resolveException(
42+
request,
43+
response,
44+
null,
45+
(Exception) request.getAttribute("swaggerCannotProdException"));
46+
} else if (request.getAttribute("exception") == null) {
4047
handleAuthenticationException(response);
4148
} else {
4249
resolver.resolveException(

src/main/java/com/gaebaljip/exceed/common/security/filter/JwtAuthenticationFilter.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.gaebaljip.exceed.common.security.filter;
22

3+
import static com.gaebaljip.exceed.common.EatCeedStaticMessage.SwaggerPatterns;
4+
35
import java.io.IOException;
46
import java.time.LocalDateTime;
57
import java.util.List;
@@ -13,12 +15,15 @@
1315
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
1416
import org.springframework.security.core.Authentication;
1517
import org.springframework.security.core.context.SecurityContextHolder;
18+
import org.springframework.util.PatternMatchUtils;
1619
import org.springframework.web.filter.OncePerRequestFilter;
1720

21+
import com.gaebaljip.exceed.common.helper.SpringEnvironmentHelper;
1822
import com.gaebaljip.exceed.common.security.domain.JwtManager;
1923
import com.gaebaljip.exceed.common.security.domain.JwtResolver;
2024
import com.gaebaljip.exceed.common.security.domain.MemberDetails;
2125
import com.gaebaljip.exceed.common.security.service.MemberDetailService;
26+
import com.gaebaljip.exceed.common.swagger.SwaggerCannotProdException;
2227

2328
import lombok.RequiredArgsConstructor;
2429
import lombok.extern.slf4j.Slf4j;
@@ -30,13 +35,22 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
3035
private final JwtManager jwtManager;
3136
private final JwtResolver jwtResolver;
3237
private final MemberDetailService memberDetailService;
38+
private final SpringEnvironmentHelper springEnvironmentHelper;
3339
private final List<String> excludeUrl = List.of("/actuator", "/v1/health");
3440

3541
@Override
3642
protected void doFilterInternal(
3743
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
3844
throws ServletException, IOException {
3945

46+
// prod 환경에서 swagger 요청을 차단
47+
if (Boolean.TRUE.equals(springEnvironmentHelper.isProdProfile())
48+
&& isSwaggerRequest(request)) {
49+
request.setAttribute(
50+
"swaggerCannotProdException", SwaggerCannotProdException.EXCEPTION);
51+
throw SwaggerCannotProdException.EXCEPTION;
52+
}
53+
4054
final String bearerToken = request.getHeader(HttpHeaders.AUTHORIZATION);
4155
if (bearerToken == null || !bearerToken.startsWith("Bearer ")) {
4256
filterChain.doFilter(request, response);
@@ -84,4 +98,9 @@ protected boolean shouldNotFilter(HttpServletRequest request) throws ServletExce
8498
}
8599
return flag;
86100
}
101+
102+
private boolean isSwaggerRequest(HttpServletRequest request) {
103+
String servletPath = request.getServletPath();
104+
return PatternMatchUtils.simpleMatch(SwaggerPatterns, servletPath);
105+
}
87106
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.gaebaljip.exceed.common.swagger;
2+
3+
import com.gaebaljip.exceed.common.exception.EatCeedException;
4+
5+
public class SwaggerCannotProdException extends EatCeedException {
6+
public static EatCeedException EXCEPTION = new SwaggerCannotProdException();
7+
8+
private SwaggerCannotProdException() {
9+
super(SwaggerError.SWAGGER_CANNOT_PROD);
10+
}
11+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.gaebaljip.exceed.common.swagger;
2+
3+
import java.lang.reflect.Field;
4+
import java.util.Objects;
5+
6+
import com.gaebaljip.exceed.common.Error;
7+
import com.gaebaljip.exceed.common.exception.BaseError;
8+
9+
import lombok.AllArgsConstructor;
10+
import lombok.Getter;
11+
12+
@Getter
13+
@AllArgsConstructor
14+
public enum SwaggerError implements BaseError {
15+
SWAGGER_CANNOT_PROD(400, "SWAGGER_400_1", "운영환경에서는 Swagger를 볼 수 없습니다."),
16+
;
17+
18+
private final Integer status;
19+
private final String code;
20+
private final String reason;
21+
22+
@Override
23+
public Error getError() {
24+
return Error.builder().reason(reason).code(code).status(status.toString()).build();
25+
}
26+
27+
@Override
28+
public String getExplainError() throws NoSuchFieldException {
29+
Field field = this.getClass().getField(this.name());
30+
ExplainError annotation = field.getAnnotation(ExplainError.class);
31+
return Objects.nonNull(annotation) ? annotation.value() : this.getReason();
32+
}
33+
}

0 commit comments

Comments
 (0)