java - 在 Swagger 中记录 Spring 的登录/注销 API

标签 java spring-boot swagger swagger-ui springfox

我正在使用 Spring Boot 开发演示 REST 服务,用户必须登录才能执行某些操作子集。使用简单配置添加 Swagger UI(使用 springfox 库)后:

@Bean
public Docket docApi() {
    return new Docket(DocumentationType.SWAGGER_2)
            .select()
                .apis(any())
                .paths(PathSelectors.ant("/api/**"))
                .build()
            .pathMapping("/")
            .apiInfo(apiInfo())
            .directModelSubstitute(LocalDate.class, String.class)
            .useDefaultResponseMessages(true)
            .enableUrlTemplating(true);
}

我最终得到了所有 api 以及 Swagger UI 页面上列出的所有操作。不幸的是,我没有在其中列出登录/注销端点。

问题是部分操作无法通过 Swagger UI 内置表单执行(我发现它非常好,希望让它发挥作用),因为用户未登录。这个问题有什么解决办法吗?我可以在 Swagger 中手动定义一些端点吗?

如果有提交凭据的表单(即登录/注销端点),我可以在使用该安全端点之前执行授权。然后,Swagger 用户可以从响应中提取 token/sessionid 并将其粘贴到通过 @ApiImplicitParams 定义的自定义查询参数。

您可以在下面找到我的安全配置:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .formLogin()
                .loginProcessingUrl("/api/login")
                .usernameParameter("username")
                .passwordParameter("password")
                .successHandler(new CustomAuthenticationSuccessHandler())
                .failureHandler(new CustomAuthenticationFailureHandler())
                .permitAll()
                .and()
            .logout()
                .logoutUrl("/api/logout")
                .logoutSuccessHandler(new CustomLogoutSuccessHandler())
                .deleteCookies("JSESSIONID")
                .permitAll()
                .and()
            .csrf()
                .disable()
            .exceptionHandling()
                .authenticationEntryPoint(new CustomAuthenticationEntryPoint())
                .and()
            .authorizeRequests()
            .and()
                .headers()
                .frameOptions()
                .disable();
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth
            .userDetailsService(userDetailsService)
            .passwordEncoder(passwordEncoder());
}

最佳答案

派对有点晚了,但由于 SpringFox 依赖 Spring bean 来构建文档,我们可以轻松地操作它。希望这可以帮助别人!

将其注册为一个bean

@Primary
@Bean
public ApiListingScanner addExtraOperations(ApiDescriptionReader apiDescriptionReader, ApiModelReader apiModelReader, DocumentationPluginsManager pluginsManager)
{
    return new FormLoginOperations(apiDescriptionReader, apiModelReader, pluginsManager);
}

用于手动添加任何操作的类:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;

import com.fasterxml.classmate.TypeResolver;
import com.google.common.collect.Multimap;

import springfox.documentation.builders.ApiListingBuilder;
import springfox.documentation.builders.OperationBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiDescription;
import springfox.documentation.service.ApiListing;
import springfox.documentation.service.Operation;
import springfox.documentation.spring.web.plugins.DocumentationPluginsManager;
import springfox.documentation.spring.web.readers.operation.CachingOperationNameGenerator;
import springfox.documentation.spring.web.scanners.ApiDescriptionReader;
import springfox.documentation.spring.web.scanners.ApiListingScanner;
import springfox.documentation.spring.web.scanners.ApiListingScanningContext;
import springfox.documentation.spring.web.scanners.ApiModelReader;

public class FormLoginOperations extends ApiListingScanner
{
    @Autowired
    private TypeResolver typeResolver;

    @Autowired
    public FormLoginOperations(ApiDescriptionReader apiDescriptionReader, ApiModelReader apiModelReader, DocumentationPluginsManager pluginsManager)
    {
        super(apiDescriptionReader, apiModelReader, pluginsManager);
    }

    @Override
    public Multimap<String, ApiListing> scan(ApiListingScanningContext context)
    {
        final Multimap<String, ApiListing> def = super.scan(context);

        final List<ApiDescription> apis = new LinkedList<>();

        final List<Operation> operations = new ArrayList<>();
        operations.add(new OperationBuilder(new CachingOperationNameGenerator())
            .method(HttpMethod.POST)
            .uniqueId("login")
            .parameters(Arrays.asList(new ParameterBuilder()
                .name("username")
                .description("The username")
                .parameterType("query")            
                .type(typeResolver.resolve(String.class))
                .modelRef(new ModelRef("string"))
                .build(), 
                new ParameterBuilder()
                .name("password")
                .description("The password")
                .parameterType("query")            
                .type(typeResolver.resolve(String.class))
                .modelRef(new ModelRef("string"))
                .build()))
            .summary("Log in") // 
            .notes("Here you can log in")
            .build());
        apis.add(new ApiDescription("/api/login/", "Authentication documentation", operations, false));

        def.put("authentication", new ApiListingBuilder(context.getDocumentationContext().getApiDescriptionOrdering())
            .apis(apis)
            .description("Custom authentication")
            .build());

        return def;
    }
}

渲染 Swagger json:

"/api/login/" : {
      "post" : {
        "summary" : "Log in",
        "description" : "Here you can log in",
        "operationId" : "loginUsingPOST",
        "parameters" : [ {
          "name" : "username",
          "in" : "query",
          "description" : "The username",
          "required" : false,
          "type" : "string"
        }, {
          "name" : "password",
          "in" : "query",
          "description" : "The password",
          "required" : false,
          "type" : "string"
        } ]
      }
    }

关于java - 在 Swagger 中记录 Spring 的登录/注销 API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34386337/

相关文章:

c# - 无效的 Swagger 安全定义

java - 我使用 RESTful 请求创建的批处理作业的详细输出的最佳实践

java - java.util.Formattable 上的示例是否不正确?

java - Akka 输入流处理

java - 如何在 Thymeleaf 中使用对象中包含的 HashMap 填充下拉列表?

java - Spring Boot + FreeMarker + RestController 加载模板

java - 休息服务不适用于 spring boot 应用程序

spring - 在@WebMvcTest 中指定@SpringBootApplication

python - Swagger - Python 客户端 - 禁用 SSL 验证

java - Swagger 与 Spring-MVC 和自定义序列化器