2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

(LIFF/React/AWS/IoT)LINEアカウントと自社サービスID/IoTデバイスを連携させる方法

Posted at

はじめに

IoTデバイスなどの自社サービス・IDとLINEアカウントを紐づけることで、通知やメッセージ送信など様々なことが可能になります。実装方法は公式リファレンスに記載されています。しかし、全て0から実装するとなると大変です。フロント・バックエンドが絡み合い、さらにはログイン画面も作らねばならず大掛かりな作業となります。ポイントを絞って実装内容を紹介致します。

事前準備

LIFFやLINEミニアプリなどの説明は割愛致します。
あらかじめ登録が必要なものです。

LINE Developersの準備

下記2点を先にLINE Developersで登録しておきましょう。
この時点ではLIFFのエンドポイントはなくても大丈夫です。

  • LINE ログイン
  • Messaging API
  • LIFFアプリの環境構築

LIFFアプリの環境構築

今回はReactで実装してます。下記コマンドを実装することでLIFFアプリを構築することができます。

$ npx @line/create-liff-app

実装方法

公式フロー図

公式リファレンスは下記のようになります。この通りに進めれば問題ありません。

image.png

フロー図をより具体化したもの

  • フロントをLIFF(React) + AWS amplify
  • バックエンドをLambda
  • DBをDynamoDB
    とした際のフロー図はこちらになります。

image.png

ゴールはどこか?

フロント(LIFF+React)側

このフローの最終目標は連携用トークンnonceを入手してユーザに下記エンドポイントにリダイレクトさせることが最終目的になります。

https://access.line.me/dialog/bot/accountLink?linkToken={LINE ID連携用トークン}&nonce={nonce}

バックエンド(AWS)側

DynamoDBなどのDBへ自社IDとLINEユーザIDを紐づけて登録することです。2回レコードの登録をする必要があります。

本レコード
nonceをキーにして仮レコードを上書きする
・自社ID
・LINEID(本登録)
・timestamp
・・・・・

連携手順

各トークンの概要

  • access_token: liff.getAccessToken()で取得できる短期トークン
  • channel_access_token = 各チャンネル固有の長期トークン
  • client_id = 各チャンネル固有の長期ID
  • 連携用トークン(link_token) = userIDとchannel access tokenを使用して入手する短期ID
  • ログイントークン = ログインに成功した際に発行される短期トークン

①LIFFアプリを開く

React等でLIFFアプリを作成してデプロイしましょう。そのLIFFアプリをチャンネルに登録することでアクセスできるようになります。

②アクセストークン(access_token)を取得する

ログインした状態でLIFFアプリを立ち上げる。その状態でliff.getAccessToken()を実行することで短期のアクセストークンを取得することができます。

③連携用トークン(link_token)を取得する lambda①

③-① アクセストークンを検証

フロント側のLIFF(React)ではトークン認証は行えません。Lambdaなどのバックエンドに処理させるようにしましょう。

検証コマンド+pythonでの実装例

curl -v -X GET 'https://api.line.me/oauth2/v2.1/verify?access_token=eyJhbG~~~'
import requests

params = {
    'access_token': 'eyJhbG~~~',
}

response = requests.get('https://api.line.me/oauth2/v2.1/verify', params=params)

レスポンス

{"client_id":"1234567890","expires_in":11111,"scope":"profile openid"

③-② ユーザIDの取得

検証済みのアクセストークンを使用します。

検証コマンド+pythonでの実装例

curl -v -X GET https://api.line.me/v2/profile -H 'Authorization: Bearer eyJhb~~~'
import requests

headers = {
    'Authorization': 'Bearer eyJhb~~~',
}

response = requests.get('https://api.line.me/v2/profile', headers=headers)

レスポンス

{"userId":"Uc000000~~","displayName":"なまえ","pictureUrl":"https://profile.line-scdn.net/hogehogehoge~~~"}

③-③ 連携用トークン(link_token)を取得

検証コマンド+pythonでの実装例

先ほど取得したuseIDとチャンネル固有のchannel access tokenを使用します。

curl -X POST https://api.line.me/v2/bot/user/{userId}/linkToken \
-H 'Authorization: Bearer {channel access token}'
import requests

headers = {
    'Authorization': 'Bearer {channel access token}',
}

response = requests.post('https://api.line.me/v2/bot/user/{userId}/linkToken', headers=headers)

レスポンス

{"linkToken":"0123456789123456789abcdefg~~~~~~"}

④自社ログイン画面へ遷移

このタイミングで自社サービスのログイン画面へ遷移します。
例としてAWS cognito + amplifyで実装できますので下記記事を参考にして頂き実装してみてください。

私が実装した例。cognito+amplifyで実装してます。
image.png

参考記事

⑤nonceを生成し、仮レコードとして登録する (lambda②)

ログインに成功したタイミングで下記内容を実行します。

  • nonceの生成
  • 仮レコードをDynamoDBに登録

⑤-① nonceの生成

nonceは最終的には削除されるものですが、LINEユーザIDと自社IDを紐づけるために一時的に必要なセキュアなキーの役割を果たします。

公式リファレンスによるnonceの要件は下記の通りです。

予測が難しく一度しか使用できない文字列であること。セキュリティ上問題があるため、自社サービスのユーザーIDなどの予測可能な値は使わないでください。
長さは10文字以上255文字以下であること
nonceとしてランダムな値を生成する際の推奨事項は以下のとおりです。

128ビット(16バイト)以上のデータで、セキュアなランダム生成関数を使う。
Base64エンコードする。
nonceは取得したユーザーIDと紐づけて保存します。

方法は要件以内で任意となります。例としてIoTデバイスなどの自社IDがある場合はそのIDをオリジナルとして、加工するのが手っ取り早いと思います。

参考記事

⑤-②仮レコードを登録

ここでは下記内容をDynamoDBへ書き込みます。

仮レコード
① 自社ID
② nonce

⑥連携完了ページへリダイレクトする

フロントの処理は最後の工程になります。
③と⑤で取得したlink_tokennonceを使用して、下記連携完了ページへリダイレクトさせます。

https://access.line.me/dialog/bot/accountLink?linkToken={LINE ID連携用トークン}&nonce={nonce}

ハマったポイント

LIFFブラウザでそのままリダイレクトさせようとすると多重ループになる場合があります。liif.openなど使い、外部ブラウザで開くように誘導を行うことで回避できます。下記私の記事です。

フロント(LIFF+React)側はこれにて終了です。

⑦結果通知 & 本レコード登録(lambda③)

アカウント連携が成功すると、ユーザには成功画面が出て、裏ではwebhookに通知がされます。
予めlambda等でエンドポイントを作成し、その内容からnonceをキーとして仮レコード内を検索して本レコードへ上書きしましょう。

LINE message API設定
image.png

LINEサーバから通知されるJSON

{
  "destination": "xxx",
  "events": [
    {
      "type": "accountLink",
      "link": {
        "result": "ok",
        "nonce": "ID連携前に作成したユニークな文字列"
      },
      "timestamp": 1647936877429,
      "source": {
        "type": "user",
        "userId": "対象のLINEユーザーID"
      },
      "replyToken": "xxx",
      "mode": "active"
    }
  ]
}
本レコード
nonceをキーにして仮レコードを上書きする
・自社ID
・LINEID(本登録)
・timestamp
・・・・・

(おまけ)Pythonでwebhookテストする方法

AWSなどではテストイベントを作ることができますが、実際にエンドポイントを叩いて確認したい場合は下記コードを実行してください。

import requests
import json

headers = {
    'Content-Type': 'application/json',
}

json_data ={
    "destination": "xxx",
    "events": [
        {
            "type": "accountLink",
            "link": {
                "result": "ok",
                "nonce": "ID連携前に作成したユニークな文字列"
            },
            "timestamp": 1647936877429,
            "source": {
                "type": "user",
                "userId": "LINEuserID"
            },
            "replyToken": "xxx",
            "mode": "active"
        }
    ]
}

print(json.dumps(json_data).encode("utf-8"))

response = requests.post('https://(webhookエンドポイント)', headers=headers, json=json_data)
print(response.text)

おわりに

無事アカウント連携できましたでしょうか? 私はIoTデバイスとアカウント連携がしたく実装したのですが、ハマるポイントが多く、情報も多くないので苦労しました。誰かの役に立てば幸いです。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?