java 无法使用 Springfox 发送授权承载令牌

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/48442416/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 10:03:43  来源:igfitidea点击:

Cannot send Authorization Bearer Token using Springfox

javaspringswaggerswagger-uispringfox

提问by paulocdf

I'm having trouble understanding why "Authorization: Bearer __" is not being sent in my api using Springfox 2.5.0. I have the following configuration:

我无法理解为什么使用 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", ",");
    }

enter image description hereAnd the curl being sent is:

在此处输入图片说明发送的卷曲是:

enter image description here

在此处输入图片说明

It seems I am unable to send "Authorization: Bearer Token" in springfox (2.5.0), is this possible?, is it a known problem?

似乎我无法在 springfox (2.5.0) 中发送“授权:不记名令牌”,这可能吗?这是已知问题吗?

Similar issue: https://github.com/springfox/springfox/issues/1812

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

PS: OpenAPI 3.0 allows the "bearer" format, example: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#jwt-bearer-sample

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

Thanks.

谢谢。

回答by Sabir Khan

I am using 2.8.0versions and below swagger configuration works for me. I mentioned in comments, everything was working fine for me for version 2.7.0but then I upgraded to 2.8.0and jwt token stopped being sent in request header. I am on Spring Boot version - 1.5.2.RELEASE.

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

Note that I wanted an UI where JWT token could be manually entered by user is format - Bearer ...and token should go in Authorizationrequest header. Its not automatically integrated with OAuth server.

请注意,我想要一个用户可以手动输入 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));
    }

}

Reference - this github issue answer by JotaroJewstar

参考 - JotaroJewstar 的这个 github 问题答案

回答by Jabari Dash

A simple workaround is to type Bearerthan paste the token after it. You will end up with a text box that contains:

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

Bearer <token>

enter image description here

在此处输入图片说明

I wish there was a more automated way. But for now, it appears as though what goes in the text box simple get's pasted into the value section of a given header entry. I suppose the reason the prefix Bearerdoes not get injected automatically is because then Swagger would be quite opinionated about which sort of authentication its users used!

我希望有一种更自动化的方式。但就目前而言,似乎文本框中的内容 simple get 已粘贴到给定标题条目的值部分。我想前缀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")]
    }
}

The REST endpoint method:

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

The curlcommand before logging in:

curl登录前的命令:

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

Response:

回复:

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

The curlcommand after logging in:

curl登录后的命令:

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

Response:

回复:

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

Note: My code is in Groovy, I am sure you can translate if you are using standard Java.

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

回答by Jorge Santos Neill

The solution that worked for me with swagger versión 2.9.2 is the following:

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

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/**");
    }

}

回答by Sunil Chauraha

I used springfox-swagger2 version-2.9.2 with below configuration and it works fine to pass JWT token via swagger-ui.

我使用具有以下配置的 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()));
}

And in controller we need to use @ApiOperation (value = "Get dummy by id.", authorizations = { @Authorization(value="apiKey") })

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

Please refer to https://github.com/springfox/springfox/issues/2194

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

回答by AmanSinghal

The below solution worked for me in swagger 2.8.0version.

以下解决方案在 swagger2.8.0版本中对我有用。

Add the below code in your Docket configuration

在您的 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());
    }

In the text box after clicking Authorizebutton in the swagger UI, type Bearer "XXXXXXXX(Token)"

Authorizeswagger UI中单击按钮后的文本框中,键入Bearer "XXXXXXXX(Token)"