LINEのMessaging APIのアカウント連携機能を使ってSHOWROOMとLINEを連携させて見た

こんにちわ。 SHOWROOMエンジニアのシミズです。
業務の合間をぬって、ひっそりとLINEのMessaging APIで遊んでいましたがそれがそこそこ形になってきました。

それがこちらです。

SHOWROOMのライブ開始をLINEに通知する

これは何かというと

  1. SHOWROOMのユーザーIDとLINEのユーザーIDを連携する
  2. SHOWROOMのお気に入りルーム情報を取得する
  3. LINEにSHOWROOMのお気に入りルームのライブ開始を通知する

というボットアプリです。(リリースするかは未定です。)

この投稿では「SHOWROOMのユーザーIDとLINEのユーザーIDを連携する」という部分について実際の画面のキャプチャを用いて解説したいと思います。

LINEのMessaging APIにはよりセキュアにLINEユーザーのアカウントとSHOWROOMなど既存サービスのユーザーアカウントを連携する仕組みが提供されており、今回はそれを利用しました。
公式のドキュメントと合わせてお読みいただければと思います。
https://developers.line.me/ja/docs/messaging-api/linking-accounts/

全体のシーケンス

f:id:otto13:20181109010648p:plain

アカウント連携開始URLを取得する

f:id:otto13:20181109000501p:plain

アカウント連携開始URLを要求するのに、リッチメニューからポストバックアクションを利用しました。
リッチメニューの「アカウント連携」ボタンを押下すると、LINEプラットフォームを経由して、我々のBotServerにリクエストが到達します。
するとBotServerはLINEプラットフォームにaccount_link_tokenを要求します。

require 'line/bot/request'
require 'line/bot/api/errors'
require 'line/bot'
class MyLineBotClient < Line::Bot::Client
  def apply_account_link_token(user_id)
    raise Line::Bot::API::InvalidCredentialsError, 'Invalidates credentials' unless credentials?

    request = Line::Bot::Request.new do |config|
      config.httpclient     = httpclient
      config.endpoint       = endpoint
      config.endpoint_path  = "/bot/user/#{user_id}/linkToken"
      config.credentials    = credentials
    end
    request.post
  end
end

rubyでこんな感じのメソッド用意してlink_tokenを取得しています。
取得したlink_tokenを組み込んで、showroomのOAuth認証ページへのURLを作成しLINEクライアントに返します。
このURLはテンプレートメッセージを利用してLINEクライアントに返し、表示しています。

SHOWROOMログイン

f:id:otto13:20181109002902p:plain

返されたURLからSHOWROOMのOAuth認証に遷移します。
SHOWROOMのログインが成功すると認可コードがBotServerに伝わって、 その認可コードを利用してaccess_tokenを取得し〜というのは一般的なOAuth2.0の認証のフロー通りです。
このOAuth2.0の仕組みをSHOWROOMに作ろうと思ったきっかけは2018年のDeNA TechConでLTさせていただきました。

SHOWROOMのイノベーションを加速させるためのマイクロサービスの取り組み

nonceを生成してLINEプラットフォームにリダイレクトさせる

LINEのドキュメントにしたがって、nonceがkeyで、SHOWROOMのユーザーIDがvalueのペアを保存しています。
ユーザーのすり替えなどを検知できるのがlink_tokenの強みなのだと思います。
ざっくりですが下記のような実装です。

Rails.cache.write("lineAccountLink:#{nonce}", sr_user_id, expires_in: expire_seconds)
redirect_to "https://access.line.me/dialog/bot/accountLink?linkToken=#{link_token}&nonce=#{nonce}

LINEプラットフォームからaccountLinkのWebhookイベントを受信する

LINEプラットフォームにリダイレクトされると、LINEプラットフォームからBotServerにaccountLinkのWebhookイベントが届きます。
このメッセージにはLINEのユーザーIDとBotServerで生成したnonceが含まれます。
nonceからSHOWROOMのユーザーIDを引き出し、そのSHOWROOMユーザーIDとLINEのユーザーIDを紐付けます。

line_user_id = event['source']['type'] == 'user' && event['source']['userId']
nonce = event['link']['result'] == 'ok' && event['link']['nonce']
if (line_user_id && nonce)
  showroom_user_id = Rails.cache.read("lineAccountLink:#{nonce}")
  User.create!(showroom_user_id: showroom_user_id, line_user_id: line_user_id)
  bot_client.link_user_rich_menu(line_user_id, account_linked_rich_menu_id) 
end

f:id:otto13:20181109010240p:plain

この連携の仕組みとは直接関係ないですが、連携完了時にリッチメニューのスイッチも行なっています。
こうすることで、連携後に利用可能となるメニューを表示させることができます。

総括

このアプリですが、はじめは一人で作っていましたが、途中からインターンとしてSHOWROOMで働いているいとう君にも参加してもらって今の状態まで持ってくることができました。 ボットプログラミング、特にLINEのボットプログラミングはクライアントのデザイン面の実装が不要なのに、ユーザービリティを追求する実装ができるのは面白かったです。
いとう君にはリッチメニュー周りの実装をまるっとやってもらいましたが、テキストメッセージのリプライによる動作から、ポストバックメッセージに変更して劇的にそっれぽいアプリになったなという印象です。
最終的に我々のBotServerは一度もHTMLを返さずに今の機能を実現できております。(アカウント連携機能が提供されてないと難しかったと思います)

途中でも述べましたが、本アプリのリリース予定は未定となります。
もしこのアプリに興味をもたれた方はどこかの現場でお声かけ下さい。
下記の現場には出現する予定です。

mirrativ.connpass.com

linedevday.linecorp.com

techcon.dena.com

最後に

SHOWROOMではエンジニアを募集しています。
SHOWROOMの機能やSHOWROOMの持つ情報を使って面白いことをしてみたいと思った人、お待ちしております。

www.wantedly.com