RailsでLIFFアプリを作る

2023/02/25

LIFF
Rails

こんにちは。

今回は、RailsでLIFFアプリを作る方法をご紹介します。

LIFFとは

LIFFは、LINEの公式アプリ内で動作するWebアプリケーションです。

LINE Front-end Framework(LIFF)は、LINEが提供するウェブアプリのプラットフォームです。このプラットフォームで動作するウェブアプリを、LIFFアプリと呼びます。
LIFFアプリを使うと、LINEのユーザーIDなどをLINEプラットフォームから取得できます。LIFFアプリではこれらを利用して、ユーザー情報を活用した機能を提供したり、ユーザーの代わりにメッセージを送信したりできます。

LIFF 公式ドキュメント

LIFFアプリのメリットとして、LINEアプリ内で動作するため、ユーザーのアプリを開く手間が省け、ログイン情報をLINEの情報を元に共有することができることが挙げられます。

webに詳しくないユーザーでも、LINEアプリを開くだけでアプリを利用できるため、ユーザーの利便性が向上します。

例えば、LINEギフトなどは、LINEアプリ内で動作するLIFFアプリです。

LIFFアプリを作る

Line DevelopersのLIFFページからLIFFアプリを作成します。

以下の公式ドキュメントを参考にしてください。

LIFFアプリの作成方法の公式ドキュメント

プロバイダーを選択し、適当なチャンネルを作成します。

チャンネルの作成

作成できたら、LIFFアプリを作成します。

この時、Endpoint URLが必要になります。

一旦ざつなURLを入力して、LIFFアプリを作成します。

RailsのcredentialsにLIFF IDを登録する

RailsでLIFFアプリを作るためには、LIFF IDを取得する必要があります。

LIFF IDは、LIFFアプリの作成時に作成されます。

EDITOR="code --wait" bin/rails credentials:edit
config/credentials.yml.enc
line:
  channel_id: XXXXXXXXXXX

上記の設定で、以下のようにAPIキーを取得することができます。

channel_id = Rails.application.credentials.dig(:line, :channel_id)

ngrokの設定

LIFFアプリを作成する際に、Endpoint URLを一旦雑に作成したと思いますが、ローカルで開発する場合は、ngrokを使って、ローカルのURLを外部に公開する必要があります。

今回は、dockerを使って、ngrokを起動します。

docker-compose.yml
version: '3.8'

services:
  ngrok:
    image: wernight/ngrok:latest
    ports:
      - 4040:4040
    environment:
      NGROK_PROTOCOL: https
      NGROK_PORT: app:3000
      NGROK_AUTH: ${NGROK_AUTH}
    depends_on:
      - app
    networks:
      - default
.env
NGROK_AUTH=xxxxxxxx

これで、ngrokが起動します。

http://localhost:4040/ にアクセスすると、ngrokのダッシュボードが表示されるのでそこから、ngrokのURLを確認します。

ngrokのダッシュボード

https://xxxxxxxxxxxx.ngrok.io が、ngrokのURLになります。

LIFFアプリのEndpoint URLを設定する

LIFFアプリのEndpoint URLを、ngrokのURLに設定します。

先ほどのLIFFアプリの作成画面に戻り、Endpoint URLを設定します。

これで、LIFF URLにアクセスすると、ngrokのURL(= ローカルのroot_path)にアクセスすることができます。

ログインする

これで、LIFF URLにアクセスするとLIFFアプリとして起動するようになりました。

ここからは、LIFFアプリの中でログインする方法を紹介します。

LIFFアプリでは、フロントエンドでIDトークンを取得し、バックエンドでそれを検証することで、ログインを実現します。

Railsアプリで実装する流れとしては

  1. フロントでIDトークンを取得する
  2. 取得したIDトークンをバックエンドに送信する
  3. バックエンドでIDトークンを検証し、IDから、DBのユーザーと紐付ける

という流れになります。

フロントでIDトークンを取得する

LIFFアプリの中で、IDトークンを取得するには、LIFF SDKを使います。

LIFF SDKは、LIFFアプリの中で、LINEの機能を利用するためのライブラリです。

LIFF SDKの公式ドキュメント

今回はStimulusを使って、LIFF SDKのイベント発火を監視しています

app/views/layouts/application.html.haml
!!!
%html
  %head
    %script{charset: "utf-8", src: "https://static.line-scdn.net/liff/edge/2/sdk.js"}
app/javascript/controllers/liff_controller.js

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["liffId", "idToken"]

  connect() {
    liff.init({
      liffId: this.liffIdTarget.value // LIFF IDを取得
    }).then(() => {
      if (!liff.isLoggedIn()) {
        liff.login();
      } else { // すでにログインしている場合は、期限切れかどうかを確認
        if (liff.getDecodedIDToken().exp < Date.now() / 1000) {
          liff.logout()
          liff.login()
        }
      }
    })
    .then(() => {
      this.idTokenTarget.value = liff.getIDToken()
    })
    .then(() => {
      setTimeout(() =>{
        this.dispatch("login")
      }, 5000)
    })
    .catch((err) => {
      console.log(err.code, err.message);
    });
  }
}

取得したIDトークンをバックエンドに送信する

app/views/sessions/new.html.haml
.flex.justify-center.pt-20
  .animate-ping.h-6.w-6.bg-blue-600.rounded-full

%p.text-ld-gray.text-center.pt-4
  ログインしています...

.hidden{'data-controller' => 'submitable liff', 'data-action' => "liff:login@window->submitable#submit"}
  = hidden_field_tag :liff_id, Rails.application.credentials.dig(:line, :liff_id), {'data-liff-target' => "liffId"}
  = form_with url: sessions_path, method: :post, local: true, data: {'submitable-target' => 'form'} do |f|
    = f.hidden_field :id_token, value: nil, data: {'liff-target' => "idToken"}
    = f.hidden_field :path, value: params[:path]
app/javascript/controllers/submitable_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = [ "form" ]

  submit() {
    this.formTarget.submit()
  }
}

LIFFログインが完了したらsubmitable_controllerのsubmitメソッドが呼ばれ、formがsubmitされます。

バックエンドでIDトークンを検証する

続いて、先ほどのフォームで送信されたIDトークンを検証します。

app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
  def new; end

  def create
    user = User.find_by_id_token!(id_token: params[:id_token])
    session[:user_id] = user.id
    flash[:success] = 'ログインしました'
    redirect_to XXX_path
  end
end
app/models/user.rb
class User < ApplicationRecord
  validates :line_id, presence: true, uniqueness: true

  def self.find_by_id_token!(id_token:)
    channel_id = Rails.application.credentials.dig(:line, :channel_id)
    uri = URI.parse('https://api.line.me/oauth2/v2.1/verify')
    params = { 'id_token' => id_token, 'client_id' => channel_id }
    res = Net::HTTP.post_form(uri, params)
    find_by!(line_id: JSON.parse(res.body)['sub'])
  end
end

line_idというレコードと、IDトークンのsubを紐付けています。

これで、sessionにuser_idが入るようになり、ログインが完了します。

ApplicationControllerにcurrent_userメソッドを追加して、ログインしているユーザーを取得できるようにします。

app/controllers/application_controller.rb
class ApplicationController < ApplicationController

  private

  def current_user
    @current_user ||= User.find_by(id: session[:user_id])
  end
  helper_method :current_user
end

まとめ

今回は、LIFFアプリを使って、LINEログインを実装しました。

LIFFアプリは、LINEの機能を使ったアプリを作るためのフレームワークです。

LIFFアプリを使うことで、LINEの機能を使ったアプリを簡単に作ることができるので、是非試してみてください。

Related Posts

[Rails] StimulusJSとTOAST UIでカレンダーを表示してみる

[Rails] StimulusJSとTOAST UIでカレンダーを表示してみる

[Rails 7.0] Stimulusのコントローラーとりあえず作っとけ5選を公開します

[Rails 7.0] Stimulusのコントローラーとりあえず作っとけ5選を公開します