---
# System prepended metadata

title: 開發 Spring Boot project 時使用 Self-Signed Certificate 以支援 https
tags: [spring]

---

# 開發 Spring Boot project 時使用 Self-Signed Certificate 以支援 https

[TOC]

###### tags: `spring`

---

在開發時常出現下列這些畫面：

![Google Chrome](https://i.imgur.com/hRzoAaY.png)
(Google Chrome)

![Mozilla Firefox](https://i.imgur.com/xkz67LJ.png)
![Mozilla Firefox](https://i.imgur.com/NEMoV2q.png)
(Mozilla Firefox)

由於開發 web application 時預設都是提供 http 服務，然而越來越多的 web services 要求專案僅能建置連線加密的環境，所以我們必須在開發期提供 https 服務。

## 憑證格式

- **JKS**<sup>[![Wikipedia](https://en.wikipedia.org/static/favicon/wikipedia.ico =16x)](https://en.wikipedia.org/wiki/Java_KeyStore "Java KeyStore")[![IETF](https://docs.oracle.com/favicon.ico =16x)](https://docs.oracle.com/javase/6/docs/technotes/tools/solaris/keytool.html "keytool")</sup>
限用於 Java 環境的專有格式。

- **PKCS &#35;12**<sup>[![Wikipedia](https://en.wikipedia.org/static/favicon/wikipedia.ico =16x)](https://en.wikipedia.org/wiki/PKCS_12 "PKCS #12")[![IETF](https://tools.ietf.org/images/rfc.png =16x)](https://tools.ietf.org/html/rfc7292 "Request for Comments: 7292")</sup>: Personal Information Exchange Syntax v1.1
業界普遍使用的格式。

### 生成 JKS

執行：

```shell
$ keytool \
-genkeypair \
-alias localhost \
-keyalg RSA \
-keysize 2048 \
-keystore keystore.jks \
-validity 3650
```

#### 將 JKS 轉為 PKCS &#35;12

執行：

```shell
$ keytool \
-importkeystore \
-srckeystore keystore.jks \
-destkeystore keystore.p12 \
-deststoretype pkcs12
```

### 直接生成 PKCS &#35;12

執行：

```shell
$ keytool \
-genkeypair \
-alias localhost \
-keyalg RSA \
-keysize 2048 \
-storetype PKCS12 \
-keystore keystore.p12 \
-validity 3650
```

接下來回答一些問題：

```
Enter keystore password:  
```

輸入至少6個字元的密碼。

```
Re-enter new password:  
```

再輸入密碼一次。

```
What is your first and last name?
  [Unknown]:  
```

輸入名字或直接按`Enter`鍵。

```
What is the name of your organizational unit?
  [Unknown]:  
```

輸入部門名稱或直接按`Enter`鍵。

```
What is the name of your organization?
  [Unknown]:  
```

輸入組織名稱或直接按`Enter`鍵。

```
What is the name of your City or Locality?
  [Unknown]:  
```

輸入地區或直接按`Enter`鍵。

```
What is the name of your State or Province?
  [Unknown]:  
```

輸入州、省或直接按`Enter`鍵。

```
What is the two-letter country code for this unit?
  [Unknown]:  
```

輸入國家或直接按`Enter`鍵。

```
Is CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct?
  [no]:  
```

輸入`yes`確認以上資訊無誤；當出現：

```
Generating 2,048 bit RSA key pair and self-signed certificate (SHA256withRSA) with a validity of 3,650 days
	for: CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
```

時表示已生成 PKCS &#35;12 keystore。

## 整合到 Spring Boot 專案

先將前面生成的 keystore 檔移或複製到 project 裡：

```
src/main/resources/keystore.(jks|p12)
```

### Server 端專案

編輯`src/main/resources/application.properties`：

```properties
# 憑證別名
server.ssl.key-alias=localhost
# 僅提供 https 服務(不使用 http)
server.ssl.enabled=true
# 憑證路徑
server.ssl.key-store=classpath:keystore.(jks|p12)
# 憑證密碼
server.ssl.key-store-password=password
# 憑證格式：JKS 或 PKCS12
server.ssl.key-store-type=PKCS12
```

### Client 端專案

編輯`src/main/resources/application.properties`：

```properties
# 憑證路徑
trust.store=classpath:keystore.p12
# 憑證密碼
trust.store.password=password
```

忘了下面這段代碼是在幹嘛的…

```java
RestTemplate restTemplate() throws Exception {
	SSLContext sslContext = new SSLContextBuilder().
		loadTrustMaterial(
			trustStore.getURL(),
			trustStorePassword.toCharArray()
		).
		build();

	SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext);

	HttpClient httpClient = HttpClients.custom().
		setSSLSocketFactory(socketFactory).
		build();

	HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);

	return new RestTemplate(factory);
}
```

## 心得

1. 考量到相容性建議還是以 **PKCS &#35;12** 為優先。
2. 建立獨立的`application(-ENVIRONMENT).properties`給不同執行環境使用。

## SpringBoot - Error parsing HTTP request header (Oauth2 https endpoints)

```
java.io.IOException: Unable to unwrap data, invalid status [CLOSED]
```

> To work Oauth2 endpoints in local you have install certs in local JRE truststore.
> Use below command to add that in local trust store:

```
$ keytool -keystore cacerts -import -trustcacerts -file "file path to cert"
```

> To make it work in postman: In chrome browser, install localhost cert to “Trusted Root Certification Authorities”

[出處](https://stackoverflow.com/questions/51501360/springboot-error-parsing-http-request-header-oauth2-https-endpoints)

