Framework/Spring

[Spring Boot]Spring Security + Swagger 연동

SHXL2 2022. 7. 31. 15:37
반응형

RestAPI의 테스트를 위해 Swagger를 연동하면서 발생했던 에러들과 해결법 공유를 위해 포스팅을 남겨봅니다.

※테스트 환경
  • Spring Boot : 2.7.2 (+Security)
  • Swagger 3.0.0

* swagger 연동을 위한 config 설정은 아래에 작성해놓았습니다.

 

swagger 연동 후 아래와 같이 swagger-ui.html로 페이지 이동이 안되는 현상이 발생했습니다.

 

연동 실패한 2.9.2 버전

<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger2</artifactId>
	<version>2.9.2</version> 
	</dependency>
<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger-ui</artifactId>
	<version>2.9.2</version>
</dependency>

검색 결과 시큐리티 인증대상에서 제외시켜주면 된다고했지만 어째서인지 실패였습니다.

 

//swagger 인증 대상에서 제외
        web.ignoring().antMatchers("/v2/api-docs",  "/configuration/ui",
			       	   "/swagger-resources", "/configuration/security",
					   "/swagger-ui.html", "/webjars/**","/swagger/**");

 

3.0.0 버전으로 업그레이드 후 다시 테스트해봤습니다.

3.0.0 버전으로 업그레이드를 할 때는 springfox-swagger2가 아닌 springfox-boot-starter 디펜던시를 주입하도록 되었습니다.

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
    <version>3.0.0</version> 
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>3.0.0</version>
</dependency>

 

이번엔 Failed to start bean 'documentationPluginsBootstrapper' 에러가 발생했습니다. 검색해보니 Spring boot 2.6버전 이후에 spring.mvc.pathmatch.matching-strategy 값이 ant_apth_matcher에서 path_pattern_parser로 변경되면서 몇몇 라이브러리(swagger포함)에 오류가 발생한다고 합니다.

 

application.properties 설정파일에 spring.mvc.pathmatch.matching-strategy=ant-path-matcher 옵션을 추가해주니 문제가 해결됐습니다.

 

연결 주소는 /swagger-ui/index.html 로 변경됐습니다. 아래 SecurityConfig와 같이 인증대상에서 Swagger 관련된 파일들을 제외하고 접속해보면 정상적으로 연결되는 것을 확인할 수 있습니다.

 

@Configuration
public class SwaggerConfig {

	private static final String API_NAME = "WENAIL API";
    private static final String API_VERSION = "1.0";
    private static final String API_DESCRIPTION = "WENAIL API 명세서";

    @Bean
    public Docket api() {
        @SuppressWarnings("deprecation")
		Parameter parameterBuilder = new ParameterBuilder()
            .name(HttpHeaders.AUTHORIZATION)
            .description("Access Tocken")
            .modelRef(new ModelRef("string"))
            .parameterType("header")
            .required(false)
            .build();

        List<Parameter> globalParamters = new ArrayList<>();
        globalParamters.add(parameterBuilder);

        return new Docket(DocumentationType.SWAGGER_2)
                .globalOperationParameters(globalParamters)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.app.wenail.rest"))
                .paths(PathSelectors.any())
                .build();
    }

    public ApiInfo apiInfo() {
	return new ApiInfoBuilder()
		.title(API_NAME)
		.version(API_VERSION)
		.description(API_DESCRIPTION)
		.build();
    }
}

 

SecurityConfig.java(Security  설정 일부)

    @Override
    public void configure(WebSecurity web) throws Exception {
    	//static 하위 파일은 인증 대상에서 제외
    	 web.ignoring().antMatchers(
         		"/css/**",
         		"/fonts/**",				
         		"/js/**",
         		"/images/**",
         		"/plugins/**/**");
        web.ignoring().antMatchers("/favicon.ico");
       
        //swagger 인증 대상에서 제외
        web.ignoring().antMatchers(
        		"/v2/api-docs",  "/configuration/ui", "/configuration/security",
				"/webjars/**","/swagger/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
    	logger.info("=====================:: WENAIL ::=====================");
    	logger.info(">> Run on Spring security");
    	logger.info("======================================================");
    	
    	http.authorizeRequests()		
				//swagger
				.antMatchers("/swagger-ui/**").permitAll()
				.antMatchers("/swagger-resources/**").permitAll()				
				
    			.antMatchers("/admin/**").hasAnyRole("ADMIN", "MASTER")    			    			
    			.anyRequest().authenticated();
		
    	//로그인 설정
		http.formLogin()
		        .loginPage("/login")
		        .loginProcessingUrl("/authenticate")
		        .failureUrl("/login?error=true")
		        .successHandler(customAuthenticationSuccessHandler)
		        .permitAll();
		
		http.logout()
		        .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
		        .logoutSuccessUrl("/login")
		        .invalidateHttpSession(true);
		
		http.exceptionHandling()
		        .accessDeniedPage("/denied");
    }
반응형