如何在Spring的端点的Swagger UI中显示所需的用户角色(访问控制信息)?

Jak*_*vba 7 spring authority roles swagger access

我在Spring中制作了一个休息api,并使用Swagger进行文档编制.最近实现了基于令牌的认证.在令牌中,有(内部)用户的角色(权限).每个控制器都注释了几个Swagger注释@PreAuthorize(some roles..)等,所以:

@ApiOperation("Delete user")
@ApiResponses(value = {
        @ApiResponse(code = 404, message = "User not found", response = ErrorResponse.class)
})
@PreAuthorize("hasAuthority('ADMIN')")
@DeleteMapping(value = "/{id}")
public ResponseEntity<?> deleteUser(@PathVariable UUID id) {
    userService.delete(id);
    return ResponseEntity.ok().build();
}
Run Code Online (Sandbox Code Playgroud)

现在,我不知道如何在我的swagger-ui中显示这些角色,因此每个端点都有信息,访问它需要哪些用户角色.我浏览过互联网,发现只有一些非常模糊的信息,大部分内容都与春天无关.

注意:我尝试使用笔记:@ApiOperation(value = "Delete user", notes = "Required roles: ADMIN, USER")显示自定义文本,但这似乎不是一种正确的方法.

小智 2

受到文章blog.codecentric.de/2018/11/springfoxswaggerextension
中的解决方案的启发 在我们的例子中,我们有由 @Secured 注释 @Secured("ROLE_Admin")装饰的控制器

我们添加了OperationNotesResourcesReader组件来添加对@ApiRoleAccessNotes的评估。
这里是完整的解决方案。

控制器

  @ApiRoleAccessNotes
  @Secured("ROLE_Admin")
  @PostMapping
  public ResponseEntity<ResponseRestDTO> createVersion(@RequestBody DraftVersionCreateDTO dto) {
    return ResponseEntity.ok()
        .body(ResponseRestDTO.builder().data(versionService.createVersion(dto))
            .message(messageService.get("version.create.ok")).build());
  }
Run Code Online (Sandbox Code Playgroud)

新的注释

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiRoleAccessNotes {
}
Run Code Online (Sandbox Code Playgroud)

然后是OperationNotesResourcesReader

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.security.access.annotation.Secured;
import org.springframework.stereotype.Component;
import com.google.common.base.Optional;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.OperationContext;
import springfox.documentation.spring.web.DescriptionResolver;
import springfox.documentation.swagger.common.SwaggerPluginSupport;

@Component
@Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER)
public class OperationNotesResourcesReader
    implements springfox.documentation.spi.service.OperationBuilderPlugin {
  private final DescriptionResolver descriptions;

  final static Logger logger = LoggerFactory.getLogger(OperationNotesResourcesReader.class);

  @Autowired
  public OperationNotesResourcesReader(DescriptionResolver descriptions) {
    this.descriptions = descriptions;
  }

  @Override
  public void apply(OperationContext context) {
    try {
      Optional<ApiRoleAccessNotes> methodAnnotation =
          context.findAnnotation(ApiRoleAccessNotes.class);
      if (!methodAnnotation.isPresent()) {
        // the REST Resource does not have the @ApiRoleAccessNotes annotation -> ignore
        return;
      }

      String apiRoleAccessNoteText;
      // get @Secured annotation
      Optional<Secured> securedAnnotation = context.findAnnotation(Secured.class);
      if (!securedAnnotation.isPresent()) {
        apiRoleAccessNoteText = "Accessible by all user roles";
      } else {
        apiRoleAccessNoteText = "Accessible by users having one of the following roles: ";
        Secured secure = securedAnnotation.get();
        for (String role : secure.value()) {
          // add the roles to the notes. Use Markdown notation to create a list
          apiRoleAccessNoteText = apiRoleAccessNoteText + "\n * " + String.join("\n * ", role);
        }
      }
      // add the note text to the Swagger UI
      context.operationBuilder().notes(descriptions.resolve(apiRoleAccessNoteText));
    } catch (Exception e) {
      logger.error("Error when creating swagger documentation for security roles: " + e);
    }
  }

  @Override
  public boolean supports(DocumentationType delimiter) {
    return SwaggerPluginSupport.pluginDoesApply(delimiter);
  }
}
Run Code Online (Sandbox Code Playgroud)