36
votes

We have our Spring Boot services behind an API Gateway. With an earlier version of Springfox - 2.1.2 we had no issues in loading the swagger-ui.html page. This worked with Spring Boot 1.4.3.RELEASE. From then, we have upgraded to Boot 1.5.7 and upgraded Springfox to 2.8.0.

Now if we load the page we get an alert box with the following long message.

Unable to infer base url. This is common when using dynamic servlet registration or when the API is behind an API Gateway. The base url is the root of where all the swagger resources are served. For e.g. if the api is available at http://example.org/api/v2/api-docs then the base url is http://example.org/api/. Please enter the location manually

I got some hints searching online, but it does not seem those situations apply to us. For one, if I simply revert back the versions, it starts working again through the same API Gateway.

Tracking the traffic, it seems calls to three XHR resources made by the .html page is causing issues. These are returning 401 from our API gateway. And the reason they return 401 is because the cookies are not passed along.

The three calls are:

If I load these URLs as pure browser requests - they work - because cookies are sent.

I doubt if CORS applies since the HTML is being served from the same address as the swagger JSON and actual service calls.

Any idea why this may be happening? Anybody faced similar issues? Suggestions for workaround? Thanks much in advance.

15

15 Answers

24
votes

Add in the security config -- following URLS that are skipped for authentication ::

private static final String[] AUTH_WHITELIST = {
        "/swagger-resources/**",
        "/swagger-ui.html",
        "/v2/api-docs",
        "/webjars/**"
};

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers(AUTH_WHITELIST);
}
22
votes

Adding below annotation at the spring boot class resolved this issue for me.

@EnableSwagger2

I am using swagger version

 <version>2.9.2</version>
8
votes

SEE EDIT BELOW

Do you use spring security?

If yes, probably you skip some resources like this (right?): "/swagger-resources/**", "/swagger-ui.html", "/v2/api-docs", "/webjars/**"

Try to change it "/swagger-resources/**" to "**/swagger-resources/**".

My specific security config for swagger is:

private static final String[] AUTH_LIST = {
        // -- swagger ui
        "**/swagger-resources/**",
        "/swagger-ui.html",
        "/v2/api-docs",
        "/webjars/**"
};

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
    .authorizeRequests().antMatchers(AUTH_LIST).authenticated()
    .and()
    .httpBasic().authenticationEntryPoint(swaggerAuthenticationEntryPoint())
    .and()
    .csrf().disable();
}

@Bean
public BasicAuthenticationEntryPoint swaggerAuthenticationEntryPoint() {
    BasicAuthenticationEntryPoint entryPoint = new BasicAuthenticationEntryPoint();
    entryPoint.setRealmName("Swagger Realm");
    return entryPoint;
}

If you need/want I can send a sample project to GitHub to you know more about my security/swagger configs.

EDIT 2018/04/10

This problem is caused by a wrong version in springfox. See this issue on github to solve the problem.

To posterity:

In pom.xml

...
<repositories>
    <repository>
        <id>swagger</id>
        <name>swagger</name>
        <url>http://oss.jfrog.org/artifactory/oss-snapshot-local</url>
    </repository>
</repositories>
...
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.8.1-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.8.1-SNAPSHOT</version>
</dependency>
...

Class that extends WebSecurityConfigAdapter:

@Configuration
public class WebSecurityConfigEntryPointApplication extends WebSecurityConfigurerAdapter {

    private static final List<String> AUTH_LIST = Arrays.asList(
            "/swagger-resources/**",
            "/swagger-ui.html**",
            "/webjars/**",
            "favicon.ico");

    @Autowired
    private RestAuthenticationEntryPoint restAuthenticationEntryPoint;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .antMatcher("/**").authorizeRequests().anyRequest().authenticated()
                .and()
                .exceptionHandling()
                .defaultAuthenticationEntryPointFor(swaggerAuthenticationEntryPoint(), new CustomRequestMatcher(AUTH_LIST))
                .and()
                .httpBasic()
                .authenticationEntryPoint(restAuthenticationEntryPoint)
                .and()
                .csrf().disable();
    }

    @Bean
    public BasicAuthenticationEntryPoint swaggerAuthenticationEntryPoint() {
        BasicAuthenticationEntryPoint entryPoint = new BasicAuthenticationEntryPoint();
        entryPoint.setRealmName("Swagger Realm");
        return entryPoint;
    }

    private class CustomRequestMatcher implements RequestMatcher {

        private List<AntPathRequestMatcher> matchers;

        private CustomRequestMatcher(List<String> matchers) {
            this.matchers = matchers.stream().map(AntPathRequestMatcher::new).collect(Collectors.toList());
        }

        @Override
        public boolean matches(HttpServletRequest request) {
            return matchers.stream().anyMatch(a -> a.matches(request));
        }

    }

}

RestAuthenticationEntryPoint:

@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
    }
}
5
votes

This happened to me, I was using SpringBoot 1.5.16 and Springfox 2.9.1.

In my application.properties, I had defined server.servlet-path=/api, but, somehow, the swagger-ui was ignoring the value defined. I've tried so many different way to make this work, and finally I found a workaround:

 @Configuration
 @EnableSwagger2
 public class SwaggerConfiguration extends WebMvcConfigurationSupport {                                    

    @Bean
    public Docket apiMonitoramento() { 
        return new Docket(DocumentationType.SWAGGER_2)
                .select()                                  
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.any())                          
                .build()    
                .apiInfo(apiInfo());
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()              
                .title("REST API")
                .description("Servicesx")               
                .build();
    }

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

I was accessing http://localhost:8080/context/swagger-ui.html, but with that configuration the correct URL is: http://localhost:8080/context/api/swagger-ui.html

3
votes

In my case, the cause of the problem was having:

@ComponentScan(basePackageClasses = {ApplicationRoot.class })

twice in two java files.

after removing the extra one, the problem went away.

2
votes

Upgrade springfox-swagger2 and springfox-swagger-ui dependencies to 2.9.2 and also ensure the basePackage is given properly

return new Docket(DocumentationType.SWAGGER_2).select()
            .apis(RequestHandlerSelectors
                .basePackage("org.abc.xyz.controller"))
            .paths(PathSelectors.regex("/.*"))
            .build().apiInfo(apiEndPointsInfo());
1
votes

I don't use spring security happened this question. My Project Use Maven Multiple Module, When access to the localhost:8080/swagger-ui.html happend this question, First I add @EnableSwagger2 in the SwaggerConf class ,Last I move @EnableSwagger to SpringBoot Application class ,this question is solved. First:

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket api(){
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.zuoyan."))
                .paths(PathSelectors.any())
                .build();
    }

}

Finally:

 @SpringBootApplication(scanBasePackages = {"com.zuoyan.springboot.appmissionhall"})
 @EnableSwagger2
public class ApplicationStartUpApplication {
    public static void main(String[] args) {
        SpringApplication.run(ApplicationStartUpApplication.class, args);
    }

}
1
votes

The solution from https://stackoverflow.com/a/56716898/13347514 by adding @EnableSwagger2WebMvc and @Import(SpringDataRestConfiguration.class) to the Main Application Class fixes my problem:

@SpringBootApplication
@EnableSwagger2WebMvc
@Import(SpringDataRestConfiguration.class)
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

}
0
votes

try with port 8080 - worked for me after i changed it to 8080

0
votes

If you do not specify any special component scan options you will face this problem if you put the class with the @EnableSwagger2 annotation in a package that is not in the hierarchy of your Spring Boot Application class (@SpringBootApplication).

Assume your Spring Boot Application class in "de.oopexpert.app", then putting @EnableSwagger2 annotated class in ...

  • de.oopexpert.app will work
  • de.oopexpert.app.config will work
  • de.oopexpert.config will NOT work

You may adapt your component scan options by adding @ComponentScan(basePackages = {"de.oopexpert"}) to specify a different root of the hierarchy.

0
votes

I added @EnableSwagger2WebMvc to the App class to fix it. I am using Spring boot 2.3.0.BUILD-SNAPSHOT and io.springfox 3.0.0-SNAPSHOT. SpringFoxConfig class stays the same.

package com.telixia.educare.academy;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

@EnableSwagger2WebMvc
@SpringBootApplication
public class AcademyApplication {

    public static void main(String[] args) {
        SpringApplication.run(AcademyApplication.class, args);
    }

}
0
votes

This could also be caused by the springfox-swagger-ui and springfox-swagger2 versions mismatch in the pom.xml, for example, if you updated one but forgot to update another:

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

You need to make sure springfox-swagger-ui and springfox-swagger2 have the same version.

0
votes

In many cases it is due to Java Version incompatibility. Many times it doesn't work with Java 11, try using Java 8

0
votes

Firstly make sure these 2 dependencies are added and then annotate your main SpringBootApplication class with @EnableSwagger2 and then your problem will be solved.

    <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>

Screen shot of main SpringBootApplication class

0
votes

I was facing the same issue with a basic Spring MVC application (no Spring Security).

I replaced

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

with

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

  }

and it did the trick