springdoc-openapi 可以应用默认的全局 SecurityScheme 吗? [英] springdoc-openapi apply default global SecurityScheme possible?

查看:900
本文介绍了springdoc-openapi 可以应用默认的全局 SecurityScheme 吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下 SecurityScheme 定义使用 springdoc-openapi for java SpringBoot RESTful 应用程序:

 @Bean公共 OpenAPI customOpenAPI() {返回新的 OpenAPI().components(new Components().addSecuritySchemes("bearer-jwt",new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT").in(SecurityScheme.In.HEADER).name("授权"))).info(new Info().title("App API").version("快照"));}

是否可以将其全局应用于所有路径,而无需添加@SecurityRequirement 注释到 @Operation 代码中随处可见的注解?

如果是,如何为不安全的路径添加排除项?

解决方案

是的,你可以在同一个地方调用addSecurityItem:

 @Bean公共 OpenAPI customOpenAPI() {返回新的 OpenAPI().components(new Components().addSecuritySchemes("bearer-jwt",new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT").in(SecurityScheme.In.HEADER).name(授权"))).info(new Info().title(App API").version(快照")).addSecurityItem(new SecurityRequirement().addList("bearer-jwt", Arrays.asList("read", "write")));}

全局安全架构可以被具有 @SecurityRequirements 注释的不同架构覆盖.包括删除操作的安全模式.例如,我们可以取消注册路径的安全性.

@SecurityRequirements@PostMapping("/注册")public ResponseEntity post(@RequestBody @Valid Registration: 注册) {返回 registrationService.register(registration);}

同时为其他 API 保留安全架构.

旧答案(2019 年 12 月 20 日):

全局安全架构可以被具有 @SecurityRequirements 注释的不同架构覆盖.但对于不安全的路径,它不能被删除.它确实在 springdoc-openapi 中缺少功能,OpenAPI 标准允许它.请参阅禁用特定操作的全局安全性

不过有一个解决方法.springdoc-openapi 具有 OpenApiCustomiser 的概念,可用于拦截生成的架构.在定制器内部,可以通过编程方式修改操作.要删除任何继承的安全性,字段 security 需要设置为空数组.该逻辑可以基于任何任意规则,例如操作名称.我使用了标签.

定制器:

import io.swagger.v3.oas.models.OpenAPI;导入 io.swagger.v3.oas.models.Operation;导入 io.swagger.v3.oas.models.PathItem;导入 org.springdoc.api.OpenApiCustomiser;导入 org.springframework.stereotype.Component;导入 javax.validation.constraints.NotNull;导入 java.util.Arrays;导入 java.util.Collections;导入 java.util.List;导入 java.util.Objects;导入 java.util.function.Function;导入 java.util.stream.Collectors;导入 java.util.stream.Stream;@成分公共类 SecurityOverrideCustomizer 实现 OpenApiCustomiser {public static final String UNSECURED =security.open";private static final List>OPERATION_GETTERS = Arrays.asList(PathItem::getGet、PathItem::getPost、PathItem::getDelete、PathItem::getHead、PathItem::getOptions, PathItem::getPatch, PathItem::getPut);@覆盖公共无效定制(OpenAPI openApi){openApi.getPaths().forEach((path, item) -> getOperations(item).forEach(operation -> {列表<字符串>标签 = operation.getTags();if (tags != null && tags.contains(UNSECURED)) {operation.setSecurity(Collections.emptyList());operation.setTags(filterTags(tags));}}));}私有静态流<操作>getOperations(PathItem pathItem) {返回 OPERATION_GETTERS.stream().map(getter -> getter.apply(pathItem)).filter(Objects::nonNull);}私有静态列表filterTags(列表<字符串>标签){返回tags.stream().filter(t -> !t.equals(UNSECURED)).collect(Collectors.toList());}}

现在我们可以将 @Tag(name = SecurityOverrideCustomizer.UNSECURED) 添加到不安全的方法中:

 @Tag(name = SecurityOverrideCustomizer.UNSECURED)@GetMapping("/open")@ResponseBody公共字符串打开(){return 它有效!";}

请记住,这只是一种解决方法.希望该问题将在下一个 springdoc-openapi 版本中得到解决(在撰写本文时,当前版本为 1.2.18).

有关工作示例,请参阅 springdoc-security-override-fix

I have the following SecurityScheme definition using springdoc-openapi for java SpringBoot RESTful app:

    @Bean
    public OpenAPI customOpenAPI() {
        return new OpenAPI()
                .components(new Components().addSecuritySchemes("bearer-jwt",
                 new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT")
                .in(SecurityScheme.In.HEADER).name("Authorization")))
                .info(new Info().title("App API").version("snapshot"));
    }

Is it possible to apply it globally to all paths, without having to go and add @SecurityRequirement annotations to @Operation annotation everywhere in the code?

If it is, how to add exclusions to unsecured paths?

解决方案

Yes, you can do it in the same place calling addSecurityItem:

  @Bean
  public OpenAPI customOpenAPI() {
    return new OpenAPI()
            .components(new Components().addSecuritySchemes("bearer-jwt",
                new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT")
                    .in(SecurityScheme.In.HEADER).name("Authorization")))
            .info(new Info().title("App API").version("snapshot"))
            .addSecurityItem(
                    new SecurityRequirement().addList("bearer-jwt", Arrays.asList("read", "write")));
  }

Global security schema can be overridden by a different one with the @SecurityRequirements annotation. Including removing security schemas for an operation. For example, we can remove security for registration path.

@SecurityRequirements
@PostMapping("/registration")
public ResponseEntity post(@RequestBody @Valid Registration: registration) {
    return registrationService.register(registration);
}

While still keeping security schemas for other APIs.

Old answer (Dec 20 '19):

Global security schema can be overridden by a different one with the @SecurityRequirements annotation. but it cannot be removed for unsecured paths. It is acctualy missing fueature in the springdoc-openapi, OpenAPI standard allows it. See disable global security for particular operation

There is a workaround though. The springdoc-openapi has a concept of an OpenApiCustomiser which can be used to intercept generated schema. Inside the customizer, an operation can be modified programmatically. To remove any inherited security, the field security needs to be set to an empty array. The logic may be based on any arbitrary rules e.g operation name. I used tags.

The customizer:

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import org.springdoc.api.OpenApiCustomiser;
import org.springframework.stereotype.Component;

import javax.validation.constraints.NotNull;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Component
public class SecurityOverrideCustomizer implements OpenApiCustomiser {

    public static final String UNSECURED = "security.open";

    private static final List<Function<PathItem, Operation>> OPERATION_GETTERS = Arrays.asList(
            PathItem::getGet, PathItem::getPost, PathItem::getDelete, PathItem::getHead,
            PathItem::getOptions, PathItem::getPatch, PathItem::getPut);

    @Override
    public void customise(OpenAPI openApi) {
        openApi.getPaths().forEach((path, item) -> getOperations(item).forEach(operation -> {
            List<String> tags = operation.getTags();
            if (tags != null && tags.contains(UNSECURED)) {
                operation.setSecurity(Collections.emptyList());
                operation.setTags(filterTags(tags));
            }
        }));
    }

    private static Stream<Operation> getOperations(PathItem pathItem) {
        return OPERATION_GETTERS.stream()
                .map(getter -> getter.apply(pathItem))
                .filter(Objects::nonNull);
    }

    private static List<String> filterTags(List<String> tags) {
        return tags.stream()
                .filter(t -> !t.equals(UNSECURED))
                .collect(Collectors.toList());
    }
}

Now we can add @Tag(name = SecurityOverrideCustomizer.UNSECURED) to unsecured methods:

    @Tag(name = SecurityOverrideCustomizer.UNSECURED)
    @GetMapping("/open")
    @ResponseBody
    public String open() {
        return "It works!";
    }

Please bear in mind that it is just a workaround. Hopefully, the issue will be resolved in the next springdoc-openapi versions (at the time of writing it the current version is 1.2.18).

For a working example see springdoc-security-override-fix

这篇关于springdoc-openapi 可以应用默认的全局 SecurityScheme 吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆