SwaggerのURLをlocalhostから特定のドメインに変更する

Swaggerは本当に便利ですね！
WEBを作る時には、常に入れたいと感じるありがたいFWです。
そのため基本的にはほぼデフォルトのままで十分使えるのですが、「Try it Out!」での接続先「localhost」を変え、検証環境や本番環境のURLを叩きたくなることもあろうかと思います。（あんまないかな？…）
ちょっとハマったので、今回はその際に設定したことを備忘録として残そうと思います。

## 今回やりたいこと
* 「Try it Out!」のボタンで検証環境や本番環境のURLを叩きたい  
![Try it Out!.png](https://qiita-image-store.s3.amazonaws.com/0/90107/c9d3dca1-7b5e-7986-719d-a8c295d602de.png)
* ちゃんと閲覧制限も設けたい

## 環境
* SpringBoot 1.5.4.RELEASE
* Java 8
* Gradle 2.13
* Swagger(springfox) 2.7.0
* Nginx 1.6.2

## SpringBootにSwaggerを導入
詳しい導入方法に関しては多数の記事がございますので、そちらをご参照いただければと思います。
ここでは、最低限の内容に留めさせていただきます。

### build.gradle

```groovy:build.gradle
.....

dependencies {
	compile('org.springframework.boot:spring-boot-starter-web')

	compile('io.springfox:springfox-swagger2:2.7.0')
	compile('io.springfox:springfox-swagger-ui:2.7.0')
}

.....
```

### SwaggerConfig.java

```java:SwaggerConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.Collections;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

	@Bean
	public Docket swaggerSpringMvcPlugin() {
		return new Docket(DocumentationType.SWAGGER_2)
				.protocols(Collections.singleton("https")) // <- ポイント 1
				.host("example.com") // <- ポイント 2
				.select()
				.apis(RequestHandlerSelectors.basePackage("対象パッケージ"))
				.build()
				.apiInfo(apiInfo());
	}

	private ApiInfo apiInfo() {
		return new ApiInfo(
				"APIのタイトル",
				"APIの詳細",
				"バージョン",
				"利用規約のURL",
				new Contact(
						"名前（会社名とか？）",
						"会社等のWebサイトURL",
						"メールアドレス"
				),
				"ライセンス",
				"ライセンスのURL",
				Collections.emptyList() /* ベンダー拡張（ ？(^^; ） */
		);
	}
}
```

ポイントはDocketに定義されている「protocols」と「host」を使うところです。
もしポートを指定したい場合は「**.host("example.com:8080")**」と書けばいいようです。
試してはいませんが、protocolsがSetなので、「http」と「https」や、他のURLスキームも可能なのかもしれません。
調べ方が悪かったのか、あまりこの情報が出てこず、ソースを追ったら見つけました♪

## 閲覧制限設定

ここまで設定して実行（本番にデプロイ）すれば、「Try it Out!」での接続先URLが変わった状態で見れるようになるかと思います。
ただ、それではセキュリティ的に問題が出そうなので、私は以下のような設定を行いました。

```conf:default.conf
# 大元設定 {{{
server {
      listen 443 default ssl;
      server_name example.com;
      # 基本設定 {{{
      server_tokens off;

      ssl on;
      ssl_certificate /etc/nginx/conf.d/ssl/example.pem;
      ssl_certificate_key /etc/nginx/conf.d/ssl/example.key;

      # }}}

      # SpringBoot設定 {{{
      location / {
          set $test 1;
          if ($http_user_agent = "ユーザーエージェントで分岐") {
            set $test 0;
          }
          if ($remote_addr = "IPで分岐") {
            set $test 0;
          }
          if ($test = 1) {
              return 404;
          }
          proxy_pass  http://localhost:ポート番号;
      } # }}}
} # }}}
```

私の場合はちょっと特殊なAPIであるため、全てでUAまたはIPの制限を入れる必要があるので上記のようにしていますが、もちろんSpringBoot側（WebSecurityConfigurerAdapterを継承して作るとか）でもOKですし、Swaggerで使用されるURLのみを制限するという方法でもOKだと思います！

### 注意点 1
Swaggerで使用されるURLのみを制限する場合、以下を対象にする必要があります。

* /v2/api-docs
* /swagger-resources*
* /swagger-ui.html
* /webjars/**

**「/v2/api-docs」**に気づかず苦戦しました。。。
表示後、/v2/api-docsのデータを展開して表示するんですね(>_<)

### 注意点 2
さすがにセッションまではいい具合にやってもらえません。。。
ここも工夫の余地がありそうです。
例えば特定のURLを叩くとUsernamePasswordAuthenticationTokenをnewしてAuthenticationManager.authenticateでセットしてくれる機能を作るとかですかね？
難しい…(´･ω･`)

## まとめ
* Docketを生成するときに「protocols」と「host」を設定すれば「Try it Out!」のURLを変えられる
* ポートはhostの引数に直接書く
* 「/v2/api-docs」から表示データは取得されるため閲覧制限時は注意する
* セッションまでは上手く操作できないので別途構築を検討する

Swaggerは他にも色々と設定できる項目があるようです。
個人勉強であれば、色々試してみたいですね！