Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何根据JavaSpring中当前的用户角色来修剪Swagger文档?_Java_Spring_Spring Boot_Swagger - Fatal编程技术网

如何根据JavaSpring中当前的用户角色来修剪Swagger文档?

如何根据JavaSpring中当前的用户角色来修剪Swagger文档?,java,spring,spring-boot,swagger,Java,Spring,Spring Boot,Swagger,我使用SpringBoot开发应用程序,使用Swagger自动生成API文档,还使用Swagger ui.html与这些API交互 我也启用了Spring安全性,并且有不同角色的用户。不同的角色可以使用不同的RESTAPI 问题:如何配置Swagger以尊重Spring的@Secured注释和修剪操作,这些操作由Swagger ui.html显示,因此只有当前用户可用的操作才可用 也就是说,想象一下下面的控制器 @RestController @Secured(ROLE_USER) public

我使用SpringBoot开发应用程序,使用Swagger自动生成API文档,还使用
Swagger ui.html
与这些API交互

我也启用了Spring安全性,并且有不同角色的用户。不同的角色可以使用不同的RESTAPI

问题:如何配置Swagger以尊重Spring的
@Secured
注释和修剪操作,这些操作由
Swagger ui.html
显示,因此只有当前用户可用的操作才可用

也就是说,想象一下下面的控制器

@RestController
@Secured(ROLE_USER)
public void SomeRestController {
  @GetMapping
  @Secured(ROLE_USER_TOP_MANAGER)
  public String getInfoForTopManager() { /*...*/ }

  @GetMapping
  @Secured(ROLE_USER_MIDDLE_MANAGER)
  public String getInfoForMiddleManager() { /*...*/ }

  @GetMapping
  public String getInfoForAnyUser() { /*...*/ }
}

无论当前用户角色如何,Swagger都将显示操作
getInfoForTopManager
GetInfoFormidManager
。如果当前经过身份验证的用户角色是
role\u user\u MIDDLE\u MANAGER
,我只希望
getinfoformidlemanager
getInfoForAnyUser
操作可以大摇大摆地使用。

好的,我认为找到了解决这个问题的好方法。解决方案由两部分组成:

  • 通过
    OperationBuilderPlugin
    扩展控制器扫描逻辑,以保留Swagger供应商扩展中的角色
  • 重写
    ServiceModelToSwigger2Mapperimpl
    bean以根据当前安全上下文筛选出操作
  • 在您的项目中,这可能看起来有点不同(即,很可能您没有类似于
    securityContextResolver
    的东西),但我相信您可以从以下代码中了解此解决方案的要点:

    第1部分:扩展控制器扫描逻辑以保留斯威格供应商扩展中的角色

    @Component
    @Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1000)
    public class OperationBuilderPluginSecuredAware implements OperationBuilderPlugin {
        @Override
        public void apply(OperationContext context) {
            Set<String> roles = new HashSet<>();
            Secured controllerAnnotation = context.findControllerAnnotation(Secured.class).orNull();
            if (controllerAnnotation != null) {
                roles.addAll(List.of(controllerAnnotation.value()));
            }
    
            Secured methodAnnotation = context.findAnnotation(Secured.class).orNull();
            if (methodAnnotation != null) {
                roles.addAll(List.of(methodAnnotation.value()));
            }
    
            if (!roles.isEmpty()) {
                context.operationBuilder().extensions(List.of(new TrimToRoles(roles.toArray(new String[0]))));
            }
        }
    
        @Override
        public boolean supports(DocumentationType delimiter) {
            return SwaggerPluginSupport.pluginDoesApply(delimiter);
        }
    }
    
    @组件
    @订单(SwaggerPluginSupport.SWAGGER\u PLUGIN\u订单+1000)
    公共类OperationBuilderPluginSecuredAware实现OperationBuilderPlugin{
    @凌驾
    公共无效应用(OperationContext上下文){
    Set roles=new HashSet();
    Secured controllerAnnotation=context.findControllerAnnotation(Secured.class).orNull();
    if(controlleranotation!=null){
    roles.addAll(List.of(controlleranotation.value());
    }
    Secured methodAnnotation=context.findAnnotation(Secured.class).orNull();
    if(methodAnnotation!=null){
    roles.addAll(List.of(methodAnnotation.value());
    }
    如果(!roles.isEmpty()){
    context.operationBuilder().extensions(新TrimToRoles(roles.toArray(新字符串[0]))的列表);
    }
    }
    @凌驾
    公共布尔支持(DocumentationType分隔符){
    返回SwaggerPluginSupport.pluginDoesApply(分隔符);
    }
    }
    
    第2部分:根据当前安全上下文筛选出操作

    @Primary
    @Component
    public class ServiceModelToSwagger2MapperImplEx extends ServiceModelToSwagger2MapperImpl {
        @Autowired
        private SecurityContextResolver<User> securityContextResolver;
    
        @Override
        protected io.swagger.models.Operation mapOperation(Operation from) {
            if (from == null) {
                return null;
            }
            if (!isPermittedForCurrentUser(findTrimToRolesExtension(from.getVendorExtensions()))) {
                return null;
            }
            return super.mapOperation(from);
        }
    
        private boolean isPermittedForCurrentUser(TrimToRoles trimToRoles) {
            if (trimToRoles == null) {
                return true;
            }
            if (securityContextResolver.hasAnyRole(trimToRoles.getValue())) {
                return true;
            }
            return false;
        }
    
        private TrimToRoles findTrimToRolesExtension(@SuppressWarnings("rawtypes") List<VendorExtension> list) {
            if (CollectionUtils.isEmpty(list)) {
                return null;
            }
            return list.stream().filter(x -> x instanceof TrimToRoles).map(TrimToRoles.class::cast).findFirst()
                    .orElse(null);
        }
    
        @Override
        protected Map<String, Path> mapApiListings(Multimap<String, ApiListing> apiListings) {
            Map<String, Path> paths = super.mapApiListings(apiListings);
            return paths.entrySet().stream().filter(x -> !x.getValue().isEmpty())
                    .collect(Collectors.toMap(x -> x.getKey(), v -> v.getValue()));
        }
    
        @Override
        public Swagger mapDocumentation(Documentation from) {
            Swagger ret = super.mapDocumentation(from);
            Predicate<? super Tag> hasAtLeastOneOperation = tag -> ret.getPaths().values().stream()
                    .anyMatch(x -> x.getOperations().stream().anyMatch(y -> y.getTags().contains(tag.getName())));
            ret.setTags(ret.getTags().stream().filter(hasAtLeastOneOperation).collect(Collectors.toList()));
            return ret;
        }
    }
    
    @Primary
    @组成部分
    公共类ServiceModelToSwigger2Mapperimplex扩展ServiceModelToSwigger2Mapperimpl{
    @自动连线
    私人SecurityContextResolver SecurityContextResolver;
    @凌驾
    受保护的io.swagger.models.Operation映射操作(来自的操作){
    if(from==null){
    返回null;
    }
    如果(!isPermittedForCurrentUser(findTrimToRolesExtension(from.getVendorExtensions())){
    返回null;
    }
    返回super.mapOperation(从);
    }
    专用布尔值isPermittedForCurrentUser(TrimToRoles TrimToRoles){
    if(trimToRoles==null){
    返回true;
    }
    if(securityContextResolver.hasAnyRole(trimToRoles.getValue())){
    返回true;
    }
    返回false;
    }
    专用TrimToRoles findTrimToRolesExtension(@SuppressWarnings(“rawtypes”)列表){
    if(CollectionUtils.isEmpty(列表)){
    返回null;
    }
    return list.stream()
    .orElse(空);
    }
    @凌驾
    受保护地图apiListings(多地图apiListings){
    映射路径=super.mapApiListings(apilings);
    返回路径.entrySet().stream().filter(x->!x.getValue().isEmpty())
    .collect(Collectors.toMap(x->x.getKey(),v->v.getValue());
    }
    @凌驾
    公共大摇大摆地图文档(来自的文档){
    Swagger-ret=super.mapDocumentation(来自);
    谓语