👨‍🔧

LINEプラットフォームの導入と運用

2023/12/08に公開

この記事は MICIN Advent Calendar 2023 の 8 日目の記事です。

https://adventar.org/calendars/9595

前回は高橋さんの、「脆弱性の早期検知と管理を内製化してみた」 でした。


MICIN では LINE プラットフォーム(以下,LINE PF)を様々な場面で導入・活用しています。

LINE は月間ユーザー数 9,500 万人[1]で,スマホユーザーの大半がインストールしているアプリです。IT 慣れしていないユーザーでも,LINE の画面は抵抗なく触れられるという方は少なくありません。高水準のアクセシビリティが求められる医療領域の Web アプリケーション開発において,LINE の活用は非常に魅力的なソリューションです。

LINE PF の詳細な仕様は公式ドキュメントに詳しく記載があります。本記事では機能の詳細な説明はできるだけ省き,LINE PF の活用を考えている方々に向けて,その概観を要所に絞って紹介します。


LINE PF を使う理由は?

MICIN での LINE PF の活用メリットは以下の 2 つです。

ユーザー体験の向上

  • ログイン時にメアド・パスワードの入力が不要
  • Web アプリケーションでも LINE にプッシュ通知を送れる

サービスのリピート率向上

  • LINE 上に自社サービスへの導線を設けられる(ユーザーのブックマークや再検索が不要になる)
  • プッシュ通知やメッセージ配信を通じてサービスの再利用を促進

MICIN は上記のメリットを得るために,LINE ログイン・メッセージ配信・LINE のトーク画面を活用しています。以下では各機能の導入と運用について説明します。

LINE ログイン

LINE ログインは文字通り,LINE のユーザー情報で自社の Web アプリケーション認証を行う機能です。OIDCプロトコルとOAuth 2.0 の認可コード付与のフローに基づいて処理が行われます。

処理の流れ

大まかな処理としては以下の 6 ステップに分類されます。

  1. Web アプリケーションからパラメータを付与の上,LINE ログインの承認画面に遷移
  2. 認証成功後にコールバック URL に遷移
  3. コールバック URL に含まれるcodeを用いて JWT 形式のtoken取得を LINE にリクエスト
  4. tokenをデコードしてユーザー関連情報を取得
  5. ユーザーの作成 or 取得find_or_create
  6. セッションの保存

手順 3 で取得できるtokenには LINE からプロバイダー単位で発行される,ユーザー ID が含まれます。また手順 6 において,サーバー上でセッションを保存することで,再認証することなくサービスを利用できます。

設定が必要な項目

コールバック URL

LINE 認証完了後の遷移・リクエスト先です。Web アプリケーションから公開用 URL を作成の上,前述の手順 1 でリクエストパラメーターに設定します。

コールバック URL は手順 3 でも利用します。この際に URL が手順 1 のリクエスト時に設定したコールバック URL と完全一致している必要があり,手順 1 と 3 で異なるパラメーター設定はできません。

Scope

手順 1 で LINE から取得したい情報をリクエストパラメーターで指定します。以下の情報を選択・取得可能です。

  • プロフィール
  • ユーザー ID
  • プロフィール画像
  • LINE の表示名
  • メールアドレス(※取得に申請が必要)

公式アカウントの追加

LINE ログインの際に,公式アカウントの友達追加を同時に行うことができます。curon でも LINE ログイン導入以降,LINE 公式アカウントのユーザー数が大幅に増加しました。リクエストパラメーターbot_promptの設定によって,LINE ログイン時の画面表示が異なります。

運用上の注意点

メッセージ機能

LINE PF ではメッセージの配信方法が大きく 3 つの形式に分かれます。

LINE 公式アカウントの
管理画面
Messaging API サービスメッセージ
※LINE ミニアプリお知らせ
利用条件 管理画面へのアクセス権 ユーザー ID とチャネルアクセストークンの取得 LINE ミニアプリの開設
送信トリガー チャット画面から任意のタイミングで送信
自動応答メッセージ
AI 応答メッセージ
自由に設定可能 LINE ミニアプリ上でユーザー操作に対する応答としてのみ送信
メッセージの配信先 公式アカウント 公式アカウント 「LINE ミニアプリ お知らせ」のアカウント
※全ての LINE ミニアプリで共通利用
配信対象 ① 公式アカウントを友達追加した全員
② 特定のユーザー群(年齢,性別等のカスタムセグメント)
① 公式アカウントを友達追加した全員
② 特定のユーザー群(年齢,性別等のカスタムセグメント)
③ 任意のユーザー
任意のユーザー
メッセージの受信 可能
※チャット機能 on の場合のみ
可能
※webhook の設定必須
N/A

Messaging API

自社のサーバーから任意のタイミングでメッセージを送りたい場合,Messaging API を利用することになります。ユーザー ID を指定して特定のユーザーへのメッセージ送信や,複数人への一斉送信も可能です。

Messaging API を利用する注意点としては大きく以下の 4 つです。

  1. メッセージの送信先は公式アカウントとユーザーのトーク画面
  2. メッセージ配信数に応じた従量課金(※1 ヶ月に 200 通まで無料)
  3. ユーザー ID とチャネルアクセストークンの取得が必要(後述)
  4. webhook で受け取ったメッセージに対する返信の場合は従量課金対象外(無料)

メッセージ送信のインターフェース自体は非常にシンプルで,以下のステップですぐに機能を試すことができます。

  1. LINE Developer コンソールから Messaging API のチャネルを開設
  2. 開設したチャネルからチャネルシークレットを取得して環境変数に設定
  3. https://api.line.me/v2/bot/message/pushに必須となるヘッダーやボディ情報を付与してリクエスト

以下は Ruby on Rails での実装例です。
※ログ保存の処理等を入れており,冗長な書き方になっています。

# 呼び出し元
# ※Userテーブル内にline_user_idを保持しており,このidで送信先を指定します
messenger = Line::Messenger.new(user:)
message = { type: 'text', text: 'test message' }
messenger.send_message(message, SecureRandom.uuid)

# app/models/line/messenger.rb
class Line::Messenger
  include ActiveModel::Model

  validates :user, presence: true

  def initialize(user: nil)
    @user = user
  end

  def send_message(message, retry_key)
    requester = Util::LineMessaging::Request.new

    response = requester.send_message(
      retry_key:,
      to: user.line_user_id,
      messages: [message],
    )

    raise Exceptions::LineMessagingFailure, response.error_message if response.status != 200

    # メッセージログをDBに保存
    LineMessagingLog.create!(
      user:,
      retry_key:,
      text: log_text(message),
      line_request_id: response.line_request_id,
    )

    true
  end

  private

  def log_text(message)
    return message[:altText] if message[:type] == 'flex'
    return message[:text] if message[:type] == 'text'

    ''
  end

  attr_reader :user
end

# lib/util/line_messaging.rb
module Util::LineMessaging
  BASE_URL = 'https://api.line.me'.freeze

  Response = Struct.new(
    :status,
    :error_message,
    :line_request_id,
    keyword_init: true,
  )

  class Request
    def send_message(retry_key:, to:, messages:, notification_disabled: false)
      requester = Faraday.new(url: BASE_URL) do |builder|
        builder.request :json
        builder.response :json
        builder.adapter Faraday.default_adapter
      end

      headers = {
        'Content-Type' => 'application/json',
        'Authorization' => "Bearer #{ENV.fetch('LINE_MESSAGING_CHANNEL_ACCESS_TOKEN')}",
        'X-Line-Retry-Key' => retry_key, # 任意の方法で生成した16進表記のUUID eg.) 123e4567-e89b-12d3-a456-426614174000
      }
      params = {
        to: to, # LINEログイン等を用いて取得したuser_idを指定
        messages: messages,
        notificationDisabled: notification_disabled,
      }
      resp = requester.post 'v2/bot/message/push', params do |request|
        request.headers = headers
      end

      Response.new(
        status: resp.status,
        error_message: resp.body['message'],
        line_request_id: resp.headers['x-line-request-id'],
      )
    end
  end
end

メッセージタイプ

Messaging API ではメッセージのカスタマイズも可能です。テキストだけでなく,画像や音声メッセージの送信はもちろんのこと,複数のメッセージタイプを組み合わせた「Flex Message」も作成可能です。

Flex Message を作成する際には,ブラウザ上で動作するシミュレーターを利用して,UI を確認しながらメッセージのカスタマイズが行えます。

シミュレーターの UI

Webhook

公式アカウントのトーク画面でユーザーが何かしらのアクション(テキストやスタンプの送信等)を行うと,LINE PF から登録済みの Webhook URL に HTTPS POST リクエストが行われます。

自社の API サーバーを用いてインタラクティブなコミュニケーションを行いたい場合,Webhook 用の公開 URL を用意して,LINE Developers の管理画面から URL 登録を行います。

以下は Ruby on Rails で作成する場合の実装例です。

# config/routes.rb
Rails.application.routes.draw do
  namespace :users do
    namespace :webhooks do
      namespace :line do
        post 'receive'
      end
    end
  end
end

# app/controllers/users/webhooks/line_controller.rb
class Users::Webhooks::LineController < ApplicationController
  def receive
    return head :bad_request unless check_signature
    return head :ok if params[:events].blank?

    user = User.find_by(line_user_id:) # ユーザーが登録済みかを検証
    return head :ok unless user
    return text_action(user) if message_params[:type] == 'message'
    return postback_action(user) if message_params[:type] == 'postback'

    head :ok
  end

  private

  # 署名の検証
  def check_signature
    CHANNEL_SECRET = '...' # Channel secret string
    http_request_body = request.raw_post # Request body string
    hash = OpenSSL::HMAC::digest(OpenSSL::Digest::SHA256.new, CHANNEL_SECRET, http_request_body)
    request.headers['X-Line-Signature'] == Base64.strict_encode64(hash)
  end

  def text_action(user)
    case receive_message
    when '登録情報'
      # 任意の処理
    when '予約状況'
      # 任意の処理
    else
      # 任意の処理
    end
  end

  def postback_action(user)
    # 任意のアクション
  end

  def message_params
    params.require(:events)[0].permit(:type, :replyToken, message: [:type, :text], source: [:userId], postback: [:data])
  end

  def receive_message
    message_params[:message][:text]
  end

  def line_user_id
    message_params[:source][:userId]
  end

  def action_params
    query_string = message_params[:postback][:data]
    URI.decode_www_form(query_string).to_h
  end
end

Messaging API では Flex Message 等を用いて作成したボタンや画像に対してアクションオブジェクトの指定ができます。その中でポストバックアクションを利用すると,上記のように任意のパラメーターを Webhook のエンドポイントに送信できます。

ピルマルでもこの仕組みを用いて予約の取得 → 確認 → 確定の一連のフローを LINE のトーク画面でインタラクティブに行っています。

予約の取得
Web アプリケーション
確認 → 確定
LINE トーク画面

上記左の画像で日時を選択すると,LINE トーク画面に選択した日時の情報が Flex Message の形式で送られます。右の画像の「予約を確定する」ボタンには,ポストバックアクションで予約日時が変数として保持されており,ボタンを押すことで Webhook 内で予約の確定処理と後続のメッセージ送信が行われる仕組みです。

サービスメッセージ

サービスメッセージは LINE ミニアプリでのみ利用可能なメッセージ機能です。メッセージ配信自体は無料となりますが,配信先が全ての公式アカウント共通で「LINE ミニアプリ お知らせ」というトーク画面になります。

メッセージ管理・運用

ピルマルのように Messaging API を多用しているサービスでは,トーク内容の確認がカスタマーサポートやデバッグなどの観点で欠かせません。Messaging API で送信したメッセージは LINE 公式アカウントのチャット機能からも確認可能です。一方でトークの中身には住所氏名などの個人情報も含まれるため,アクセス権を必要最低限にを絞る必要があります。

そこで,ピルマルでは以下の方針でメッセージ管理・運用を行っています。

  • ユーザーの問い合わせ窓口は原則メールと電話を利用
  • 管理画面上でのチャット返信は原則行わない
  • 管理画面上へのアクセス権は運用担当者など必要最小限に絞る
  • DB には API サーバー経由で送信したメッセージを暗号化して保存
  • 医師 → 患者への予約キャンセル通知等,必要な機能に限ってメッセージ送信用の UI を実装

企業対ユーザーの関係において,1 人の担当者が対応できるユーザー数には限界があります。Messaging API は従量課金という特性も踏まえて,できる限り効率的かつ,ユーザー体験を損ねない設計を意識した管理・運用を実施しています。

フロントエンドの比較

自社でサーバーサイドの API を開発・運用している前提で,LINE PF を活用した Web アプリケーションのフロントエンドの特徴をまとめました。

一般的な Web アプリケーション LINE
公式アカウント
   LINE   
ミニアプリ
   LIFF     
アプリ
UI/UX 自由に設計 トーク画面
リッチメニュー
自由だが一部制限有 自由だが一部制限有
ホスティング 必須 不要 不要 不要
審査 不要 不要 必須 不要
ブラウザ Chrome, Safari など 不要 LIFF ブラウザ LIFF ブラウザ
利用導線 ブックマーク,検索 LINE の友達一覧 LINE トーク画面 LINE トーク画面
外部サイトへの遷移 可能 可能 制限有り 制限有り
ユースケース 小〜大規模の開発 予約,チャットなど限定された機能開発 小〜中規模の開発 小〜中規模の開発

LINE PF を用いたフロントエンド開発

機能要求の側面だけ考えると,LINE PF を用いたフロントエンド開発は UI/UX,ホスティング,ブラウザなどの制限事項が少なくありません。特にLIFF ブラウザではデバイスのハードウェアに関する機能(カメラや Bluetooth へのアクセス)に制限事項が多いです。

開発・運用工数の観点では,フロントエンドをホスティングするサーバーを LINE が用意してくれている点で,運用が楽という考え方もできます。しかし一般的な Web アプリケーションに比べて LINE PF を用いた開発工数に大きな違いはありません。むしろ LINE PF 独自の API や仕様の理解が必要という点では,工数が多少増える印象です。

一方でサービスを一度利用すれば LINE 上から再アクセスしやすいという点は,URL ベースの Web アプリケーションには無いメリットです。

MICIN での LINE PF の活用

MICIN のサービスでもこれらの特性を考慮して,自前での Web アプリケーション+公式アカウント+Messaging API の構成でプロダクトの開発・運用を行っています。

 サービス名  サービスの基本機能
※LINE 外で実装
サービスの
認証方式
LINE PF の利用目的
クロンお薬サポート 予約,ビデオ通話,決済,配送 メアド・LINE・Apple LINE ログインした場合,メールの代わりとして LINE に通知
ピルマル 予約,決済 LINE のみ LINE ログインでの認証
チャットでの機能利用誘導
個人情報・配送情報の表示 UI

LIFF アプリと LINE ミニアプリの違い

LINE ミニアプリと LIFF アプリは,LIFF(LINE Front-end Framework)上で実行される、ウェブアプリケーションです。その違いは大きく以下の 3 点です。

LIFF アプリ LINE ミニアプリ
公開審査 不要 必須
サービスメッセージの利用 不可 可能
LINE アプリ上からの検索 不可 可能

LINE PF の活用を進める上で

LINE PF は多岐にわたるソリューションを提供していることもあり,ソリューションの取捨選択や理解に時間がかかります。特に仕様の理解・共有という面ではエンジニアが詳細を確認し,メリット・デメリット,できること・できないことをプロダクトマネージャーやデザイナー,場合によってはビジネスサイドのメンバーにもインプットしなければなりません。

弊社でも公式ドキュメントの度重なる確認,社内向けの機能比較ドキュメントの作成を行い,MTG を重ねる中でメンバー内での LINE PF に関する理解度を深めています。本記事はその中で整理された知見をまとめて執筆しました。本記事を通じて,皆様の LINE PF を用いたプロダクト開発や事業開発が促進されると幸いです。


MICIN ではメンバーを大募集しています。
「とりあえず話を聞いてみたい」でも大歓迎ですので、お気軽にご応募ください!
MICIN 採用ページ:https://recruit.micin.jp/

脚注
  1. 公式サイトから参照 ↩︎

株式会社MICIN

Discussion