Spring Boot 和 Swagger 用户界面。设置 JWT 令牌

新手上路,请多包涵

我有一个像这样的 Swagger 配置

@EnableSwagger2
@Configuration
public class SwaggerConfig {
    @Bean
    public Docket api() {
        List<SecurityScheme> schemeList = new ArrayList<>();
        schemeList.add(new ApiKey(HttpHeaders.AUTHORIZATION, "JWT", "header"));
        return new Docket(DocumentationType.SWAGGER_2)
                .produces(Collections.singleton("application/json"))
                .consumes(Collections.singleton("application/json"))
                .ignoredParameterTypes(Authentication.class)
                .securitySchemes(schemeList)
                .useDefaultResponseMessages(false)
                .select()
                .apis(Predicates.not(RequestHandlerSelectors.basePackage("org.springframework.boot")))
                .paths(PathSelectors.any())
                .build();
    }
}

在 Swagger UI 中,当我单击 Authorize 按钮时,我在值字段 eyJhbGc..nN84qrBg 中输入我的 JWT 令牌。现在我希望我通过 Swagger UI 执行的任何请求都将在标头中包含 JWT。然而,事实并非如此。没有请求包含授权标头。

我错过了什么?

原文由 isADon 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
2 个回答

原始答案

支持 Authorization: Bearer [JWT_TOKEN] 标头从版本 2.9.2 开始工作

将以下依赖项添加到 build.gradle

 compile("io.springfox:springfox-swagger2:2.9.2") {
    exclude module: 'mapstruct' // necessary in my case to not end up with multiple mapstruct versions
}
compile "io.springfox:springfox-bean-validators:2.9.2"
compile "io.springfox:springfox-swagger-ui:2.9.2"

通过配置 Swagger

 @Configuration
@EnableSwagger2
@Import(springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration.class)
public class SwaggerConfiguration {

    public static final String AUTHORIZATION_HEADER = "Authorization";
    public static final String DEFAULT_INCLUDE_PATTERN = "/api/.*";
    private final Logger log = LoggerFactory.getLogger(SwaggerConfiguration.class);

    @Bean
    public Docket swaggerSpringfoxDocket() {
        log.debug("Starting Swagger");
        Contact contact = new Contact(
            "Matyas Albert-Nagy",
            "https://justrocket.de",
            "matyas@justrocket.de");

        List<VendorExtension> vext = new ArrayList<>();
        ApiInfo apiInfo = new ApiInfo(
            "Backend API",
            "This is the best stuff since sliced bread - API",
            "6.6.6",
            "https://justrocket.de",
            contact,
            "MIT",
            "https://justrocket.de",
            vext);

        Docket docket = new Docket(DocumentationType.SWAGGER_2)
            .apiInfo(apiInfo)
            .pathMapping("/")
            .apiInfo(ApiInfo.DEFAULT)
            .forCodeGeneration(true)
            .genericModelSubstitutes(ResponseEntity.class)
            .ignoredParameterTypes(Pageable.class)
            .ignoredParameterTypes(java.sql.Date.class)
            .directModelSubstitute(java.time.LocalDate.class, java.sql.Date.class)
            .directModelSubstitute(java.time.ZonedDateTime.class, Date.class)
            .directModelSubstitute(java.time.LocalDateTime.class, Date.class)
            .securityContexts(Lists.newArrayList(securityContext()))
            .securitySchemes(Lists.newArrayList(apiKey()))
            .useDefaultResponseMessages(false);

        docket = docket.select()
            .paths(regex(DEFAULT_INCLUDE_PATTERN))
            .build();
        watch.stop();
        log.debug("Started Swagger in {} ms", watch.getTotalTimeMillis());
        return docket;
    }

    private ApiKey apiKey() {
        return new ApiKey("JWT", AUTHORIZATION_HEADER, "header");
    }

    private SecurityContext securityContext() {
        return SecurityContext.builder()
            .securityReferences(defaultAuth())
            .forPaths(PathSelectors.regex(DEFAULT_INCLUDE_PATTERN))
            .build();
    }

    List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope
            = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        return Lists.newArrayList(
            new SecurityReference("JWT", authorizationScopes));
    }
}

通过 http://host:port/<context-root>/swagger-ui.html 访问用户界面

按 Authorize all requests 并输入 Bearer [JWT_TOKEN]

按授权,然后输入 Bearer JWT Token

瞧,您的下一个请求将具有 JWT 标头

在此处输入图像描述

2022-09-24 更新

在一系列较新的项目之后,我开始使用 springdoc-openapi 生成基于 javadoc 的文档,从而消除了额外注释的需要。

为任何愿意尝试这个库的人写这篇文章。我会推荐它/我是这个库的快乐用户。

依赖项

build.gradle

 [...]
// swagger ui
implementation 'org.springdoc:springdoc-openapi-ui:1.6.9'
implementation 'org.springdoc:springdoc-openapi-javadoc:1.6.9'
annotationProcessor 'com.github.therapi:therapi-runtime-javadoc-scribe:0.13.0'
implementation 'com.github.therapi:therapi-runtime-javadoc:0.13.0'
[...]

声明身份验证

使用项目特定的 SecurityConfiguration.java 定义OpenAPI授权的模式。本例: BearerAuthorization 在 HTTP 中 header

 import static io.swagger.v3.oas.annotations.enums.SecuritySchemeIn.HEADER;
import static io.swagger.v3.oas.annotations.enums.SecuritySchemeType.HTTP;
import io.swagger.v3.oas.annotations.security.SecurityScheme;

 @Component
 @SecurityScheme(name = SecurityConfiguration.SECURITY_CONFIG_NAME, in = HEADER, type = HTTP, scheme = "bearer", bearerFormat = "JWT")
 public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
 [...]
     public static final String SECURITY_CONFIG_NAME = "App Bearer token";
 [...]

在 REST 控制器中的使用

SomeController.java 中的用法应参考安全配置

import static com.x.common.security.SecurityConfiguration.SECURITY_CONFIG_NAME;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;

 @RestController
 @RequestMapping("/api/v1/resources")
 @SecurityRequirement(name = SECURITY_CONFIG_NAME)
 public class ConnectionSyncController {

     /**
      * Documentation that will be rendered
      *
      * supports
      *
      * 1. markdown
      * 1. list
      */
     @PostMapping("/{id}/sync")
     @DomainAuthorize(permissionType = BasePermissions.PERM_ADMIN_OPERATIONS)
     public void syncConnection(@PathVariable("id") Long id) {

配置可达性

  1. 配置openapi规范的位置(swagger yml)-默认 /v3/api-docs
  2. 配置 swagger-ui 的位置/加载配置
  3. 配置哪些后端 swagger-ui 可以对话
  4. 如果我们在代理后面,我们需要确保调用使用正确的标头进行代理,以便一切正常工作。

/src/main/resources/application.yml

  server:
   port: 80
   # needed for swagger-ui to detect correct proxied paths correctly.
   # Configuration needed for the [Try out] buttons to work
   # this works in combination with the proxied headers
   # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   # proxy_set_header X-Forwarded-Prefix /services/impower-facilioo;
   forward-headers-strategy: FRAMEWORK

 springdoc:
   swagger-ui:
     # where the UI configuration is located at
     configUrl: /[some/public/path]/v3/api-docs/swagger-config
     filter: true
     deepLinking: true
     # where the server API yml/json files are at (dropdown in top right corner)
     urls[0]:
       url: /[some/public/path]/v3/api-docs
       name: backend

原文由 Matyas 发布,翻译遵循 CC BY-SA 4.0 许可协议

你的代码是正确的。

springfox-swagger-ui / springfox-swagger2 版本 2.8.0 中有一个 错误,它似乎也是 2.9.2。我怀疑您正在使用受此错误影响的版本。

我只是降级到 2.7.0 ,它运行良好。

原文由 rjdkolb 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进