스웨거 문서 외부용/내부용 분리

hongo·2024년 7월 24일
0

@ExternalAPI 를 통해 외부용/내부용 API 구분

커스텀 어노테이션인 @ExternalAPI를 생성하고,
@ExternalAPI 가 붙여진 API만 외부에 공개되도록 설정했다.

  • @ExternalAPI 가 API 메서드단에 붙여져있다면, 해당 API만 외부에 공개된다.
  • @ExternalAPI 가 컨트롤러 클래스단에 붙여져있다면, 해당 컨트롤러의 모든 API가 외부에 공개된다.

Docket 설정

Docket을 사용해 스웨거 문서를 생성할 수 있다.

groupName, apis등 여러 개의 체인 메서드를 통해 문서에 대한 커스텀 설정이 가능하다.

적용한 커스텀 설정은 다음과 같다.

groupName

Docket 빈을 여러개 생성하면 그만큼 다양한 스웨거 문서가 생성된다.

이 때 각 Docket에는 groupName 명시해줘야한다. Docket이 하나만 있을 때는 default라는 이름으로 자동 생성되지만, 여러 개를 만들면 각 Docket들을 구분하기 위해 groupName을 필수로 지정해줘야 한다.

// 예시 코드
  
  return new Docket(DocumentationType.SWAGGER_2)
          .select()
          .apis(basePackagePredicate)
          .paths(PathSelectors.any()).build()
          .groupName("external") // groupName 지정 필요
          .apiInfo(apiInfo());

생성된 스웨거 문서를 보면 오른쪽 상단에서 groupName 메서드에 인자로 넣은 이름으로 만들어진 각 문서들을 볼 수 있다. 아래 사진의 예시는 internalexternal 이라는 groupName을 가진 두 개의 Docket을 생성한 결과이다.

스웨거 문서 우측 상단의 Select a spec 을 눌러서 여러 개의 스웨거 문서 중 하나를 선택해서 조회할 수 있다.

apis

외부용 스웨거 문서는 메서드나 클래스단에 @ExternalAPI 가 붙여진 API들만 응답해야한다.

Docket의 체인 메서드 apis 에서는 스웨거 문서에서 어떤 api들을 보여줄 것인지를 지정할 수 있다.

RequestHandlerSelectors 를 사용해 @ExternalAPI 가 메서드와 클래스에 붙여진 API만 조회할 수 있게 설정해주었다.

// 예시 코드

return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(Predicates.and( // @ExternalAPI가 붙여진 API만 지정
                        basePackagePredicate,
                        Predicates.or(
                                RequestHandlerSelectors.withMethodAnnotation(ExternalAPI.class),
                                RequestHandlerSelectors.withClassAnnotation(ExternalAPI.class)
                        )
                ))
                .paths(PathSelectors.any()).build()
                .groupName("external")
                .apiInfo(apiInfo());

swagger html 경로와 정적 파일 매핑

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
}

내부용 문서 인증 추가

내부용 문서 접근시 spring security를 사용한 간단한 Basic인증을 수행하게 설정했다.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Value("${swagger.username}")
    private String SWAGGER_USERNAME;

    @Value("${swagger.password}")
    private String SWAGGER_PASSWORD;

		// 내부용 문서에 한해서만 인증 적용
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .requestMatchers(new SwaggerGroupNameRequestMatcher("internal"))
                    .authenticated()
                .and()
                .httpBasic();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .inMemoryAuthentication()
                .withUser(SWAGGER_USERNAME).password("{noop}" + SWAGGER_PASSWORD).roles("USER");
    }
}

// {noop}은 비밀번호를 별다른 인코딩없이 저장하겠다는 의미로, 없으면 인코더가 없어서 에러가 발생한다.
// 보안이 낮지만 예시용으로 ~~₩.............. 
public class SwaggerGroupNameRequestMatcher implements RequestMatcher {
    private final String groupName;

    public SwaggerGroupNameRequestMatcher(String groupName) {
        this.groupName = groupName;
    }

		// 스웨거 API 문서 조회 API이면서, group 쿼리 파라미터가 멤버 변수값과 같을 때만 매칭 
    @Override
    public boolean matches(HttpServletRequest request) {
        String urlPath = request.getServletPath();
        String urlParameter = request.getParameter("group");
        return urlPath.equals("/v2/api-docs") && groupName.equals(urlParameter);
    }
}
		// maven 의존성 추가
		
		<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-config -->
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-config</artifactId>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-web -->
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-web</artifactId>
		</dependency>
profile
https://github.com/hgo641

0개의 댓글