在开发 Rest API 时,经常会使用 Swagger 进行 API 测试,但是 API 通常情况下都是受保护的,需要携带 token 才能访问,本文将介绍在 Spring Boot 中,Swagger 集成 OAuth2 服务。

本文所使用的环境:

  • Java8
  • Spring Boot 2.0
  • Spring OAuth2
  • Keycloak OAuth2 认证服务器
  • Gradle

首先是 swagger 的配置:

package me.javaroad.mcloud.apigw.config;

import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.OAuthBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.AuthorizationCodeGrant;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.GrantType;
import springfox.documentation.service.SecurityScheme;
import springfox.documentation.service.TokenEndpoint;
import springfox.documentation.service.TokenRequestEndpoint;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger.web.ApiKeyVehicle;
import springfox.documentation.swagger.web.SecurityConfiguration;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    private static final String VERSION = "1.0";

    @Value("${swagger.title:API Gateway}")
    private String title;
    @Value("${swagger.description:}")
    private String description;
    private final KeycloakProperties keycloakProperties;

    public SwaggerConfig(KeycloakProperties keycloakProperties) {
        this.keycloakProperties = keycloakProperties;
    }

    @Bean
    public Docket apiDocket() {
        return new Docket(DocumentationType.SWAGGER_2)
            .select()
            .apis(RequestHandlerSelectors.basePackage("me.javaroad.mcloud.apigw"))
            .paths(PathSelectors.any())
            .build()
            .apiInfo(apiInfo())
            .securitySchemes(Collections.singletonList(oauth()))
            ;
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
            .title(title)
            .description(description)
            .license("Apache 2.0")
            .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
            .termsOfServiceUrl("")
            .version(VERSION)
            .build();
    }

    @Bean
    List<GrantType> grantTypes() {
        List<GrantType> grantTypes = new ArrayList<>();
        TokenRequestEndpoint tokenRequestEndpoint = new TokenRequestEndpoint(
            keycloakProperties.getClient().getUserAuthorizationUri(),
            keycloakProperties.getClient().getClientId(), keycloakProperties.getClient().getClientSecret());
        TokenEndpoint tokenEndpoint = new TokenEndpoint(keycloakProperties.getClient().getAccessTokenUri(), "access_token");
        grantTypes.add(new AuthorizationCodeGrant(tokenRequestEndpoint, tokenEndpoint));
        return grantTypes;
    }

    @Bean
    SecurityScheme oauth() {
        return new OAuthBuilder()
            .name("OAuth2")
            .scopes(scopes())
            .grantTypes(grantTypes())
            .build();
    }

    private List<AuthorizationScope> scopes() {
        return Lists.newArrayList(new AuthorizationScope("openid", "Grants openid access"));
    }

    @Bean
    public SecurityConfiguration securityInfo() {
        return new SecurityConfiguration(keycloakProperties.getClient().getClientId(),
            keycloakProperties.getClient().getClientSecret(),
            "realm", keycloakProperties.getClient().getClientId(),
            "apiKey", ApiKeyVehicle.HEADER, "api_key", "");
    }
}

application.yml

oauth2:
  keycloak:
    client:
      client-id: mcloud-demo
      client-secret: 123456
      user-authorization-uri: http://localhost:8443/auth/realms/mcloud/protocol/openid-connect/auth
      access-token-uri: http://localhost:8443/auth/realms/mcloud/protocol/openid-connect/token

最后,我们需要在 keycloak 的 客户端设置中配置 swagger 的回调地址:

http://localhost/webjars/springfox-swagger-ui/o2c.html

image

此处需要注意配置允许跨域(第二个红框)

所有的配置到此结束,如果一切正常,访问 swagger ,将看到以下页面:

这里写图片描述

点击 Authorize 按钮后,我们就会跳转到 keycloak 进行登陆授权:

这里写图片描述

成功登陆并授权后,页面又会跳会 swagger,此时我们访问受保护的 API 时,swagger 会自动带上 access_token 作为参数:

这里写图片描述

本篇教程就到此结束,如需查看源码,请参考:
GitHub