【问题标题】:Cannot send Authorization Bearer Token using Springfox无法使用 Springfox 发送授权承载令牌
【发布时间】:2025-12-05 23:35:01
【问题描述】:

我无法理解为什么没有使用 Springfox 2.5.0 在我的 api 中发送“授权:承载 __”。我有以下配置:

private ApiKey apiKey() {
        return new ApiKey(
                "Authorization", // name: My key - Authorization
                "api_key", // keyname: api_key
                "header");
    }

@Bean
    SecurityConfiguration security() {
        return new SecurityConfiguration(
                null, null, null,
                "Docserver2_fwk", // app name
                "BEARER", // api key value
                ApiKeyVehicle.HEADER, "Authorization", ",");
    }

发送的卷曲是:

似乎我无法在 springfox (2.5.0) 中发送“Authorization: Bearer Token”,这可能吗?这是一个已知问题吗?

类似问题:https://github.com/springfox/springfox/issues/1812

PS:OpenAPI 3.0 允许“承载”格式,例如:https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#jwt-bearer-sample

谢谢。

【问题讨论】:

  • 您应该尝试迁移到 springfox 2.8.0。和 springfox-swagger-ui 2.8.0。我相信它应该可以解决您的问题。至于不记名令牌,您仍然需要在令牌前面加上 Bearer
  • 感谢您的回答,但我仅限于使用具有 springfox 2.5.0 的客户端库。客户端不会更改 springfox 版本,因为它会影响其他几个应用程序。虽然我对springfox版本没有控制,但是我用的是最新的springfox-swagger-ui。
  • 另一件事,如果我在令牌前面加上“Bearer”,我会得到“Authorization Bearer:”而不是“Authorization: Bearer”(注意冒号)。
  • 我的意思是在键值中:不要单独使用键,而是使用Bearer <key>
  • 啊,是的,这行得通,但这不是一个理想的解决方案,因为它会迫使使用该界面的人知道他们必须编写“Bearer ”而不是仅仅粘贴文本字段中的标记。

标签: java spring swagger swagger-ui springfox


【解决方案1】:

一个简单的解决方法是键入Bearer,而不是在其后粘贴令牌。您最终会得到一个包含以下内容的文本框:

Bearer <token>

我希望有一种更自动化的方式。但就目前而言,似乎文本框中简单获取的内容已粘贴到给定标题条目的值部分。我想前缀 Bearer 没有自动注入的原因是因为 Swagger 会非常固执己见地决定其用户使用哪种身份验证!

@Configuration
@EnableSwagger2
class SwaggerConfig {

    @Bean
    Docket api() {

        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(Predicates.not(PathSelectors.regex("/error.*")))
                .build()
                .securitySchemes(securitySchemes())
    }

    private static ArrayList<? extends SecurityScheme> securitySchemes() {

        return [new ApiKey("Bearer", "Authorization", "header")]
    }
}

REST 端点方法:

@GetMapping("/count")
@ApiOperation(value = "Count the number of entities associated with resource name. This operation does not requires any role." , authorizations = [@Authorization(value = "Bearer")])
def count() {

    count(service)
}

登录前的curl命令:

curl -X GET "http://localhost:8080/category/count" -H "accept: */*"

回复:

{
  "timestamp": "2018-10-29T15:13:02.388+0000",
  "status": 401,
  "error": "Unauthorized",
  "message": "Unauthorized",
  "path": "/category/count"
}

登录后的curl命令:

curl -X GET "http://localhost:8080/category/count" -H "accept: */*" -H "Authorization: Bearer eyJhbGciOiJIUzUxMiJ9..."

回复:

{
  "message": "There are 0 entities",
  "count": 0
}

注意:我的代码是用 Groovy 编写的,如果您使用标准 Java,我相信您可以翻译。

【讨论】:

    【解决方案2】:

    我正在使用2.8.0 版本和以下招摇配置适用于我。我在 cmets 中提到,对于我来说,2.7.0 版本一切正常,但后来我升级到2.8.0,并且 jwt 令牌停止在请求标头中发送。我使用的是 Spring Boot 版本 - 1.5.2.RELEASE

    请注意,我想要一个用户可以手动输入 JWT 令牌的 UI 格式 - Bearer ... 并且令牌应该放在 Authorization 请求标头中。它不会自动与 OAuth 服务器集成。

    import java.time.LocalDate;
    import java.util.Arrays;
    import java.util.List;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    
    import springfox.documentation.builders.ApiInfoBuilder;
    import springfox.documentation.builders.PathSelectors;
    import springfox.documentation.builders.RequestHandlerSelectors;
    import springfox.documentation.service.ApiInfo;
    import springfox.documentation.service.ApiKey;
    import springfox.documentation.service.AuthorizationScope;
    import springfox.documentation.service.SecurityReference;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spi.service.contexts.SecurityContext;
    import springfox.documentation.spring.web.plugins.Docket;
    import springfox.documentation.swagger.web.SecurityConfiguration;
    import springfox.documentation.swagger.web.SecurityConfigurationBuilder;
    import springfox.documentation.swagger2.annotations.EnableSwagger2;
    
    import com.google.common.base.Predicates;
    import com.google.common.collect.Lists;
    
    @Configuration
    @EnableSwagger2
    public class SwaggerConfig extends WebMvcConfigurerAdapter {
    
        @SuppressWarnings("unchecked")
        @Bean
        public Docket swaggerPlugin() {
        return new Docket(DocumentationType.SWAGGER_2)
            .select()
            .paths(PathSelectors.any())
            .apis(Predicates.or(RequestHandlerSelectors
                .basePackage("**controller package 1**"),
                RequestHandlerSelectors
                    .basePackage("**controller package 2**")))
            .build().directModelSubstitute(LocalDate.class, String.class)
            .genericModelSubstitutes(ResponseEntity.class)
            .apiInfo(apiInfo())
            .securitySchemes(Lists.newArrayList(apiKey()))
            .securityContexts(Arrays.asList(securityContext()));
        }
    
        private ApiInfo apiInfo() {
        return new ApiInfoBuilder().title("**Comment**")
            .description("**Comment**")
            .termsOfServiceUrl("**Comment**")
            .contact("**Comment**")
            .license("Apache License Version 2.0")
            .licenseUrl("**Comment**").version("0.0.1")
            .build();
        }
    
        @Bean
        public SecurityConfiguration security() {
        return SecurityConfigurationBuilder.builder().scopeSeparator(",")
            .additionalQueryStringParams(null)
            .useBasicAuthenticationWithAccessCodeGrant(false).build();
        }
    
        @Override
        public void addResourceHandlers(final ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html").addResourceLocations(
            "classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations(
            "classpath:/META-INF/resources/webjars/");
        }
    
        private ApiKey apiKey() {
        return new ApiKey("apiKey", "Authorization", "header");
        }
    
        private SecurityContext securityContext() {
        return SecurityContext.builder().securityReferences(defaultAuth())
            .forPaths(PathSelectors.any()).build();
        }
    
        private List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope(
            "global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        return Arrays.asList(new SecurityReference("apiKey",
            authorizationScopes));
        }
    
    }
    

    参考 - this github issue answer by JotaroJewstar

    【讨论】:

      【解决方案3】:

      从 Springfox 3.0.0 开始,这种授权有专用的 HttpAuthenticationScheme 配置。

      JWT 授权配置示例:

      @Bean
      public Docket jwtSecuredDocket() {
          HttpAuthenticationScheme authenticationScheme = HttpAuthenticationScheme
                  .JWT_BEARER_BUILDER
                  .name("JWT Token")
                  .build();
          
          return new Docket(DocumentationType.OAS_30)
                  // <...>
                  .securitySchemes(Collections.singletonList(authenticationScheme));
      }
      

      这是一个更方便的解决方案,因为您不必每次都在 Swagger UI 的身份验证模式中输入“Bearer”关键字 - 新机制为您填补了这一点(这是以前解决方案的一个缺点)。

      重要提示

      根据commit introducing this feature 的消息,必须将案卷的DocumentationType 设置为OAS_30 才能使其正常工作。

      【讨论】:

        【解决方案4】:

        我正在使用最新版本的 springfox(现在是 3.0.0),您可以使用特定的承载身份验证和 HttpAuthenticationScheme 而不是 ApiKey:

        HttpAuthenticationScheme
            .JWT_BEARER_BUILDER
            .name("JWT")
            .build()
        

        【讨论】:

        • 这段代码放在哪一部分?你能提供更多的上下文吗?我正在尝试在 springfox 3.0.0 中设置授权标头
        • @mindOf_L 当然。我在配置类中的案卷初始化时应用它。示例:lang-kt @Configuration class SwaggerConfig { ... @Bean fun docket(): Docket = Docket(...) .apiInfo(...) ... ..securitySchemes(listOf(HttpAuthenticationScheme.JWT_BEARER_BUILDER...) }
        • 这会在映射安全定义时引发空指针异常。无法使用这个
        • 这是否适用于 documentationType.Swagger2 或 OAS30
        • 无法正常工作 - 获取空指针。看起来错误就在这里:在 springfox.documentation.swagger2.mappers.SecurityMapper.toSecuritySchemeDefinitions(SecurityMapper.java:53) ~[springfox-swagger2-3.0.0.jar:3.0.0]
        【解决方案5】:

        使用 swagger 版本 2.9.2 对我有用的解决方案如下:

        package com.example.springsocial;
        
        import java.util.Arrays;
        import java.util.Collections;
        import java.util.List;
        
        import org.springframework.context.annotation.Bean;
        import org.springframework.context.annotation.Configuration;
        import org.springframework.security.core.annotation.AuthenticationPrincipal;
        import com.google.common.base.Predicates;
        import com.google.common.collect.Lists;
        
        import springfox.documentation.builders.PathSelectors;
        import springfox.documentation.builders.RequestHandlerSelectors;
        import springfox.documentation.service.ApiKey;
        import springfox.documentation.service.AuthorizationScope;
        import springfox.documentation.service.SecurityReference;
        import springfox.documentation.spi.DocumentationType;
        import springfox.documentation.spi.service.contexts.SecurityContext;
        import springfox.documentation.spring.web.plugins.Docket;
        import springfox.documentation.swagger2.annotations.EnableSwagger2;
        
        @Configuration
        @EnableSwagger2
        public class SwaggerConfiguration   {
        
            @Bean
            public Docket docket() {
                return new Docket(DocumentationType.SWAGGER_2)
                            .ignoredParameterTypes(AuthenticationPrincipal.class)
                            .select()
                            .apis(Predicates.not(RequestHandlerSelectors.basePackage("org.springframework.boot")))
                            .paths(PathSelectors.any()).build()
                            .securitySchemes(Lists.newArrayList(apiKey()))
                            .securityContexts(Arrays.asList(securityContext()));
        
            }
        
            private ApiKey apiKey() {
                return new ApiKey("apiKey", "Authorization", "header");
            }
        
            private SecurityContext securityContext() {
                return SecurityContext.builder().securityReferences(defaultAuth())
                    .forPaths(PathSelectors.any()).build();
            }
        
            private List<SecurityReference> defaultAuth() {
                AuthorizationScope authorizationScope = new AuthorizationScope(
                    "global", "accessEverything");
                AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
                authorizationScopes[0] = authorizationScope;
                return Arrays.asList(new SecurityReference("apiKey",
                    authorizationScopes));
                }
        }
        

        POM.XML

        <!-- SWAGGER  -->
                <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>
                <dependency>
                    <groupId>io.springfox</groupId>
                    <artifactId>springfox-bean-validators</artifactId>
                    <version>2.9.2</version>
                </dependency>
        

        SecurityConfig.JAVA

        package com.example.springsocial.config;
        
        import com.example.springsocial.security.*;
        import com.example.springsocial.security.oauth2.CustomOAuth2UserService;
        import com.example.springsocial.security.oauth2.HttpCookieOAuth2AuthorizationRequestRepository;
        import com.example.springsocial.security.oauth2.OAuth2AuthenticationFailureHandler;
        import com.example.springsocial.security.oauth2.OAuth2AuthenticationSuccessHandler;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.context.annotation.Bean;
        import org.springframework.context.annotation.Configuration;
        import org.springframework.security.authentication.AuthenticationManager;
        import org.springframework.security.config.BeanIds;
        import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
        import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
        import org.springframework.security.config.annotation.web.builders.HttpSecurity;
        import org.springframework.security.config.annotation.web.builders.WebSecurity;
        import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
        import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
        import org.springframework.security.config.http.SessionCreationPolicy;
        import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
        import org.springframework.security.crypto.password.PasswordEncoder;
        import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
        
        @Configuration
        @EnableWebSecurity
        @EnableGlobalMethodSecurity(
                securedEnabled = true,
                jsr250Enabled = true,
                prePostEnabled = true
        )
        public class SecurityConfig extends WebSecurityConfigurerAdapter {
        
            @Autowired
            private CustomUserDetailsService customUserDetailsService;
        
            @Autowired
            private CustomOAuth2UserService customOAuth2UserService;
        
            @Autowired
            private OAuth2AuthenticationSuccessHandler oAuth2AuthenticationSuccessHandler;
        
            @Autowired
            private OAuth2AuthenticationFailureHandler oAuth2AuthenticationFailureHandler;
        
            @Autowired
            private HttpCookieOAuth2AuthorizationRequestRepository httpCookieOAuth2AuthorizationRequestRepository;
        
            @Bean
            public TokenAuthenticationFilter tokenAuthenticationFilter() {
                return new TokenAuthenticationFilter();
            }
        
            /*
              By default, Spring OAuth2 uses HttpSessionOAuth2AuthorizationRequestRepository to save
              the authorization request. But, since our service is stateless, we can't save it in
              the session. We'll save the request in a Base64 encoded cookie instead.
            */
            @Bean
            public HttpCookieOAuth2AuthorizationRequestRepository cookieAuthorizationRequestRepository() {
                return new HttpCookieOAuth2AuthorizationRequestRepository();
            }
        
            @Override
            public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
                authenticationManagerBuilder
                        .userDetailsService(customUserDetailsService)
                        .passwordEncoder(passwordEncoder());
            }
        
            @Bean
            public PasswordEncoder passwordEncoder() {
                return new BCryptPasswordEncoder();
            }
        
        
            @Bean(BeanIds.AUTHENTICATION_MANAGER)
            @Override
            public AuthenticationManager authenticationManagerBean() throws Exception {
                return super.authenticationManagerBean();
            }
        
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http
                        .cors()
                            .and()
                        .sessionManagement()
                            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                            .and()
                        .csrf()
                            .disable()
                        .formLogin()
                            .disable()
                        .httpBasic()
                            .disable()
                        .exceptionHandling()
                            .authenticationEntryPoint(new RestAuthenticationEntryPoint())
                            .and()
                        .authorizeRequests()
                            .antMatchers("/",
                                "/error",
                                "/favicon.ico",
                                "/**/*.png",
                                "/**/*.gif",
                                "/**/*.svg",
                                "/**/*.jpg",
                                "/**/*.html",
                                "/**/*.css",
                                "/**/*.js",
                                // swagger
                                "/swagger-ui.html**", "/swagger-resources/**",
                                "/v2/api-docs**", "/webjars/**"
                                 )
                                .permitAll()
                            .antMatchers("/auth/**", "/oauth2/**")
                                .permitAll()
                            .anyRequest()
                                .authenticated()
                            .and()
                        .oauth2Login()
                            .authorizationEndpoint()
                                .baseUri("/oauth2/authorize")
                                .authorizationRequestRepository(cookieAuthorizationRequestRepository())
                                .and()
                            .redirectionEndpoint()
                                .baseUri("/oauth2/callback/*")
                                .and()
                            .userInfoEndpoint()
                                .userService(customOAuth2UserService)
                                .and()
                            .successHandler(oAuth2AuthenticationSuccessHandler)
                            .failureHandler(oAuth2AuthenticationFailureHandler);
        
                // Add our custom Token based authentication filter
                http.addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
            }
        
            @Override
            public void configure(WebSecurity web) throws Exception {
                web.ignoring().antMatchers("/common/**", "/v2/api-docs", "/configuration/ui", "/swagger-resources",
                        "/configuration/security", "/swagger-ui.html", "/webjars/**");
            }
        
        }
        

        【讨论】:

          【解决方案6】:

          我使用 springfox-swagger2 version-2.9.2 和以下配置,通过 swagger-ui 传递 JWT 令牌可以正常工作。

          private ApiKey apiKey() {    
              return new ApiKey("apiKey", Authorization, "header"); 
          }
          
          @Bean
          public Docket api() {
              return new Docket(DocumentationType.SWAGGER_2).select()
                 .apis(RequestHandlerSelectors.basePackage("com.mycompany.dept.controller"))
                 .paths(PathSelectors.any())
                 .build().apiInfo(metaData()).securitySchemes(Lists.newArrayList(apiKey()));
          }
          

          在控制器中我们需要使用@ApiOperation (value = "Get dummy by id.", authorizations = { @Authorization(value="apiKey") })

          请参考https://github.com/springfox/springfox/issues/2194

          【讨论】:

            【解决方案7】:

            以下解决方案在 swagger 2.8.0 版本中对我有用。

            在您的 Docket 配置中添加以下代码

            @Bean
                public Docket api() {
                    return new Docket(DocumentationType.SWAGGER_2)
                            .securitySchemes(Collections.singletonList(new ApiKey("JWT", "Authorization", "header")))
                            .securityContexts(Collections.singletonList(
                                    SecurityContext.builder()
                                            .securityReferences(
                                                    Collections.singletonList(SecurityReference.builder()
                                                            .reference("JWT")
                                                            .scopes(new AuthorizationScope[0])
                                                            .build()
                                                    )
                                            )
                                            .build())
                            )
                            .select()
                            .apis(RequestHandlerSelectors
                                    .basePackage("com.test.controller"))
                            .paths(PathSelectors.regex("/.*"))
                            .build().apiInfo(apiEndPointsInfo());
                }
            

            在swagger UI中点击Authorize按钮后的文本框中,输入Bearer "XXXXXXXX(Token)"

            【讨论】:

              【解决方案8】:

              另一个使用 springfox 3.0.0 的工作解决方案。

              import java.util.Arrays;
              import java.util.Collections;
              import java.util.List;
              import javax.servlet.ServletContext;
              import org.springframework.beans.factory.annotation.Autowired;
              import org.springframework.context.annotation.Bean;
              import org.springframework.context.annotation.Configuration;
              import springfox.documentation.builders.PathSelectors;
              import springfox.documentation.builders.RequestHandlerSelectors;
              import springfox.documentation.oas.annotations.EnableOpenApi;
              import springfox.documentation.service.AuthorizationScope;
              import springfox.documentation.service.HttpAuthenticationScheme;
              import springfox.documentation.service.SecurityReference;
              import springfox.documentation.spi.DocumentationType;
              import springfox.documentation.spi.service.contexts.SecurityContext;
              import springfox.documentation.spring.web.plugins.Docket;
              
              @Configuration
              @EnableOpenApi
              public class SwaggerConfig {
                  
                  @Autowired
                  private ServletContext context;
              
                  @Bean
                  public Docket api() {       
                      HttpAuthenticationScheme authenticationScheme = HttpAuthenticationScheme.JWT_BEARER_BUILDER
                              .name("Authorization")
                              .build();
              
                      return new Docket(DocumentationType.OAS_30)
                              .select()
                              .apis(RequestHandlerSelectors.any())
                              .paths(PathSelectors.ant(context.getContextPath() + "/api/**"))
                              .build()
                              .securityContexts(Arrays.asList(securityContext()))
                              .securitySchemes(Collections.singletonList(authenticationScheme));
                  }
              
                  private SecurityContext securityContext() {
                      return SecurityContext.builder().securityReferences(defaultAuth()).build();
                  }
              
                  private List<SecurityReference> defaultAuth() {
                      AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
                      AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
                      authorizationScopes[0] = authorizationScope;
                      return Arrays.asList(new SecurityReference("Authorization", authorizationScopes));
                  }
              
              }
              

              【讨论】:

                【解决方案9】:

                Jorge Santos Neill 提供的解决方案对我有用。

                唯一的变体是我的 SecurityConfig.java,如下所述

                import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
                import org.springframework.context.annotation.Configuration;
                import org.springframework.security.config.annotation.web.builders.HttpSecurity;
                import org.springframework.security.config.annotation.web.builders.WebSecurity;
                import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
                import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
                import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
                
                @EnableWebSecurity
                @EnableResourceServer
                @EnableOAuth2Sso
                @Configuration
                
                public class SecurityConfig extends WebSecurityConfigurerAdapter {
                
                    @Override
                    protected void configure(final HttpSecurity http) throws Exception {
                        http.authorizeRequests().anyRequest().authenticated().and().csrf().disable();
                    }
                
                    @Override
                    public void configure(WebSecurity web) throws Exception {
                    web.ignoring().antMatchers("/v2/api-docs", "/configuration/**", "/configuration/ui/**", "/swagger-resources/**",
                            "/configuration/security/**", "/swagger-ui.html", "/webjars/**", "/health", "/csrf");
                
                    }
                
                }
                

                【讨论】: