【问题标题】:springdoc-openapi apply default global SecurityScheme possible?springdoc-openapi 应用默认全局 SecurityScheme 可能吗?
【发布时间】:2020-04-08 22:49:13
【问题描述】:

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

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

是否可以将其全局应用于所有路径,而无需在代码中的任何位置将@SecurityRequirement 注释添加到@Operation 注释?

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

【问题讨论】:

    标签: java spring swagger openapi springdoc


    【解决方案1】:

    是的,您可以在同一个地方拨打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")));
      }
    

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

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

    同时仍保留其他 API 的安全架构。

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

    全局安全模式可以被带有@SecurityRequirements 注释的不同模式覆盖。但对于不安全的路径,它不能被删除。 springdoc-openapi 中确实缺少功能,OpenAPI 标准允许这样做。见disable global security for particular operation

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

    定制器:

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

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

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

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

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

    【讨论】:

    【解决方案2】:

    使用 springdoc-openapi v1.2.29 测试:可以使用 @SecurityRequirements 禁用特定端点的安全性

    @GetMapping("/open")
    @ResponseBody
    @SecurityRequirements
    public String open() {
        return "It works!";
    }
    

    对于旧版本,例如使用 OperationCustomizer 使用 v1.2.28 进行测试:

    public static final String UNSECURED = "security.open";
    
    @Bean
    public OperationCustomizer customize() {
        return (Operation operation, HandlerMethod handlerMethod) -> {
            List<String> tags = operation.getTags();
            if (tags != null && tags.contains(UNSECURED)) {
                operation.setSecurity(Collections.emptyList());
                operation.setTags(tags.stream()
                        .filter(t -> !t.equals(UNSECURED))
                        .collect(Collectors.toList()));
            }
            return operation;
        };
    }
    

    【讨论】:

      猜你喜欢
      • 2020-04-20
      • 2022-11-10
      • 2020-10-02
      • 2020-07-07
      • 2021-10-17
      • 1970-01-01
      • 1970-01-01
      • 2022-10-18
      • 2020-06-25
      相关资源
      最近更新 更多