line-bot-sdk-java 自社サービスユーザーとLINEユーザーのアカウント連携

[line-bot-sdk-java](https://github.com/line/line-bot-sdk-java)を使用した、自社サービスの既存ユーザーアカウントとLINEユーザーのアカウントの連携手順についてメモ。
`※記事内のソースは例外処理等記述してないので、注意。`

[サンプルソースコード](https://github.com/try0/line-bot-java-sample/blob/main/line-bot-java-app/src/main/java/jp/try0/line/bot/sample/app/resource/WebhookResource.java)

[アカウント連携のシーケンス](https://developers.line.biz/ja/docs/messaging-api/linking-accounts/#%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E9%80%A3%E6%90%BA%E3%81%AE%E3%82%B7%E3%83%BC%E3%82%B1%E3%83%B3%E3%82%B9)で、アカウントを連携する手順についてドキュメントが用意されています。
ここを確認しながら実装する。

以下モジュールを使用しました。

```xml
<dependency>
	<groupId>com.linecorp.bot</groupId>
	<artifactId>line-bot-servlet</artifactId>
	<version>4.3.0</version>
</dependency>
<dependency>
	<groupId>com.linecorp.bot</groupId>
	<artifactId>line-bot-model</artifactId>
	<version>4.3.0</version>
</dependency>
<dependency>
	<groupId>com.linecorp.bot</groupId>
	<artifactId>line-bot-parser</artifactId>
	<version>4.3.0</version>
</dependency>
```

![sequence.63cc462d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92451/c1953912-a733-c155-26f7-a15686ba6644.png)


フォーローイベントを受け取ったら、連携用のメッセージを返す形で進める。


**1 Call API to issue link token**
**2 Return link token**
フォローイベントを受け取ったら、LINEのユーザーIDを元にリンクトークンを取得します。

```java
LineMessagingClient client = LineMessagingClient.builder("yourAccessToken").build();
// アカウント連携用トークン取得
IssueLinkTokenResponse linkTokenRes = client.issueLinkToken(event.getSource().getUserId()).get();
String lineLinkToken = linkTokenRes.getLinkToken();
```

**3 Call API to send linking URL**
自社サービスのログインフォームが表示できるようユーザーへTemplateMessageを返します。
ログインフォームへリンクトークンをパラメーターで渡します。
※[連携解除について](https://developers.line.biz/ja/docs/messaging-api/linking-accounts/#%E9%80%A3%E6%90%BA%E8%A7%A3%E9%99%A4%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)
※ユーザーがアカウントを連携するときに、連携解除機能があることを通知すること


```java
// 自社サービスのユーザー認証画面を表示するボタン付きのメッセージを返す
List<Action> actions = Arrays.asList(new URIAction("連携する",
			URI.create("https://yourdomain/loginform?linkToken=" + lineLinkToken), null));
String botResponseText = "LINEと連携するアカウント情報をフォームに入力してください。";
TemplateMessage templateMessage = new TemplateMessage("アカウント連携",
					new ButtonsTemplate(null, "アカウント連携", botResponseText, actions));

TextMessage textMessage = new TextMessage("連携はいつでも解除可能です。");

ReplyMessage rep = new ReplyMessage(event.getReplyToken(), Arrays.asList(templateMessage, textMessage));

// TODO reply message
```


**4 Send linking URL**
LINEユーザーが、3で送信したTemplateMessageを受け取ります。


**5 Access linking URL**
**6 Show login form**
LINEユーザーが、4で受け取ったメッセージのアカウント連携ボタンをクリックして、自社サービスのログインフォームを表示します。

**7 Enter credentials**
**[8 Get user ID and generate nonce](https://developers.line.biz/ja/docs/messaging-api/linking-accounts/#verifying-user-id)**
自社サービスのユーザー認証処理を通し、Nonceを生成します。

**9 Redirect to account link endpoint**
**10 Access account link endpoint**
8でリクエストを処理したら、以下URLへリダイレクトするようレスポンスを返却します。

```
https://access.line.me/dialog/bot/accountLink?linkToken=[2で受け取ったlink token]&nonce=[8で生成したNonce]
```





**11 Send webhook event**
**12 Link accounts**
アカウント連携イベントを受け取ったら、8で生成したNonceから自社サービスのユーザーを判定しLINEユーザーIDと紐づけます。
※[連携解除について](https://developers.line.biz/ja/docs/messaging-api/linking-accounts/#%E9%80%A3%E6%90%BA%E8%A7%A3%E9%99%A4%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6)
※ユーザーに連携解除機能を必ず提供すること

```java
LinkContent linkContent = event.getLink();

if (linkContent.getResult() == Result.OK) {

    String nonce = linkContent.getNonce();

    // TODO 自社サービスで生成したNonceでユーザー判定

    // TODO 自社サービスのユーザーIDとラインユーザーIDをセットで保存する

    TextMessage textMessage = new TextMessage("LINE連携が完了しました。");

    List<Action> actions = Arrays
            .asList(new PostbackAction("解除する", "unlinkAccount"));

    TemplateMessage templateMessage = new TemplateMessage("アカウント連携解除",
            new ButtonsTemplate(null, "アカウント連携解除", "アカウントの連携を解除する場合は、以下ボタンをクリックしてください。", actions));

    ReplyMessage rep = new ReplyMessage(event.getReplyToken(), Arrays.asList(textMessage, templateMessage));

    // TODO reply message

}

TextMessage textMessage = new TextMessage("連携失敗");
ReplyMessage rep = new ReplyMessage(event.getReplyToken(), Arrays.asList(textMessage));

// TODO reply message
```


これで、自社サービスユーザーとLINEユーザーのアカウント連携が完了。
公式のドキュメントが詳細に記述されていて、わかりやすい。