Skip to content

Commit

Permalink
Merge pull request #610 from JNU-econovation/feat/#603
Browse files Browse the repository at this point in the history
[BE/FEAT] 스웨거 비밀번호 설정
  • Loading branch information
LJH098 authored Jan 4, 2025
2 parents e13a899 + 9051323 commit fdc5bff
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,14 @@ public class EatCeedStaticMessage {
public static final String REDIS_REFRESH_TOKEN_KEY = "refresh_";

public static final String REFRESH_TOKEN = "refreshToken";
public static final String[] SwaggerPatterns = {
"/swagger-resources/**",
"/swagger-ui/**",
"/swagger-ui.html",
"/v3/api-docs/**",
"/v3/api-docs",
"/api-docs/**",
"/api-docs",
"/docs/api-doc.html"
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.gaebaljip.exceed.common.helper;

import java.util.Arrays;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import lombok.RequiredArgsConstructor;

@Component
@RequiredArgsConstructor
public class SpringEnvironmentHelper {

private final Environment environment;

private final String PROD = "prod";
private final String STAGING = "staging";
private final String DEV = "dev";
private final List<String> PROD_AND_STAGING = List.of("staging", "prod");

public Boolean isProdProfile() {
String[] activeProfiles = environment.getActiveProfiles();
List<String> currentProfile = Arrays.stream(activeProfiles).toList();
return currentProfile.contains(PROD);
}

public Boolean isStagingProfile() {
String[] activeProfiles = environment.getActiveProfiles();
List<String> currentProfile = Arrays.stream(activeProfiles).toList();
return currentProfile.contains(STAGING);
}

public Boolean isDevProfile() {
String[] activeProfiles = environment.getActiveProfiles();
List<String> currentProfile = Arrays.stream(activeProfiles).toList();
return currentProfile.contains(DEV);
}

public Boolean isProdAndStagingProfile() {
String[] activeProfiles = environment.getActiveProfiles();
List<String> currentProfile = Arrays.stream(activeProfiles).toList();
return CollectionUtils.containsAny(PROD_AND_STAGING, currentProfile);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsUtils;

import com.gaebaljip.exceed.common.helper.SpringEnvironmentHelper;
import com.gaebaljip.exceed.common.security.domain.JwtManager;
import com.gaebaljip.exceed.common.security.domain.JwtResolver;
import com.gaebaljip.exceed.common.security.exception.JwtAccessDeniedHandler;
Expand All @@ -29,6 +30,7 @@ public class SecurityConfig {
private final MemberDetailService memberDetailService;
private final JwtAuthenticationPoint jwtAuthenticationPoint;
private final JwtAccessDeniedHandler jwtAccessDeniedHandler;
private final SpringEnvironmentHelper springEnvironmentHelper;

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
Expand Down Expand Up @@ -77,12 +79,22 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.permitAll()
.antMatchers(HttpMethod.POST, "/v1/auth/login", "/v1/auth/refresh")
.permitAll()
.antMatchers(
"/swagger-resources/**",
"/swagger-ui/**",
"/swagger-ui.html",
"/v3/api-docs/**",
"/v3/api-docs",
"/api-docs/**",
"/api-docs")
.permitAll()
.anyRequest()
.authenticated();

// jwt filter 설정
http.addFilterBefore(
new JwtAuthenticationFilter(jwtManager, jwtResolver, memberDetailService),
new JwtAuthenticationFilter(
jwtManager, jwtResolver, memberDetailService, springEnvironmentHelper),
UsernamePasswordAuthenticationFilter.class);
return http.build();
}
Expand All @@ -91,16 +103,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) ->
web.ignoring()
.antMatchers("/docs/api-doc.html")
.antMatchers("/favicon.*", "/*/icon-*")
.antMatchers(
"/swagger-resources/**",
"/swagger-ui/**",
"/swagger-ui.html",
"/v3/api-docs/**",
"/v3/api-docs",
"/api-docs/**",
"/api-docs")
.requestMatchers(PathRequest.toStaticResources().atCommonLocations());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,14 @@ public void commence(
HttpServletResponse response,
AuthenticationException authException)
throws IOException {
if (request.getAttribute("exception") == null) {

if (request.getAttribute("swaggerCannotProdException") != null) {
resolver.resolveException(
request,
response,
null,
(Exception) request.getAttribute("swaggerCannotProdException"));
} else if (request.getAttribute("exception") == null) {
handleAuthenticationException(response);
} else {
resolver.resolveException(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.gaebaljip.exceed.common.security.filter;

import static com.gaebaljip.exceed.common.EatCeedStaticMessage.SwaggerPatterns;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
Expand All @@ -13,12 +15,15 @@
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.PatternMatchUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import com.gaebaljip.exceed.common.helper.SpringEnvironmentHelper;
import com.gaebaljip.exceed.common.security.domain.JwtManager;
import com.gaebaljip.exceed.common.security.domain.JwtResolver;
import com.gaebaljip.exceed.common.security.domain.MemberDetails;
import com.gaebaljip.exceed.common.security.service.MemberDetailService;
import com.gaebaljip.exceed.common.swagger.SwaggerCannotProdException;

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

@Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {

// prod 환경에서 swagger 요청을 차단
if (Boolean.TRUE.equals(springEnvironmentHelper.isProdProfile())
&& isSwaggerRequest(request)) {
request.setAttribute(
"swaggerCannotProdException", SwaggerCannotProdException.EXCEPTION);
throw SwaggerCannotProdException.EXCEPTION;
}

final String bearerToken = request.getHeader(HttpHeaders.AUTHORIZATION);
if (bearerToken == null || !bearerToken.startsWith("Bearer ")) {
filterChain.doFilter(request, response);
Expand Down Expand Up @@ -84,4 +98,9 @@ protected boolean shouldNotFilter(HttpServletRequest request) throws ServletExce
}
return flag;
}

private boolean isSwaggerRequest(HttpServletRequest request) {
String servletPath = request.getServletPath();
return PatternMatchUtils.simpleMatch(SwaggerPatterns, servletPath);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.gaebaljip.exceed.common.swagger;

import com.gaebaljip.exceed.common.exception.EatCeedException;

public class SwaggerCannotProdException extends EatCeedException {
public static EatCeedException EXCEPTION = new SwaggerCannotProdException();

private SwaggerCannotProdException() {
super(SwaggerError.SWAGGER_CANNOT_PROD);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.gaebaljip.exceed.common.swagger;

import java.lang.reflect.Field;
import java.util.Objects;

import com.gaebaljip.exceed.common.Error;
import com.gaebaljip.exceed.common.exception.BaseError;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum SwaggerError implements BaseError {
SWAGGER_CANNOT_PROD(400, "SWAGGER_400_1", "운영환경에서는 Swagger를 볼 수 없습니다."),
;

private final Integer status;
private final String code;
private final String reason;

@Override
public Error getError() {
return Error.builder().reason(reason).code(code).status(status.toString()).build();
}

@Override
public String getExplainError() throws NoSuchFieldException {
Field field = this.getClass().getField(this.name());
ExplainError annotation = field.getAnnotation(ExplainError.class);
return Objects.nonNull(annotation) ? annotation.value() : this.getReason();
}
}

0 comments on commit fdc5bff

Please sign in to comment.