はじめに
Railsの7系にLIFF(Line Front-end Framework)を組み込んだアプリを開発したのですが、下記の点からかなり苦戦しました。
・LIFF特有の構文への自身の不慣れさ
・Rails7ではアセット管理の方法が様々な種類がある
・RailsでLIFFを活用するための参考資料の不足
そこで今回は、Railsを使用してLINEを組み込んだアプリを作成したい方に向けて、LIFFの活用方法について解説する記事を作成しました。
この記事では、実際の手順に沿ってハンズオン形式で学習を進めていきます。
参考にしていただければ幸いです。
今回作成するのは、トップページに設置したボタンを押すだけでログインができ、ログイン前後でページの内容が切り替わるというシンプルなアプリケーションです。
記事を通じて以下のトピックに触れていきます:
・LIFF(Line Front-end Framework)
・LINEログイン
・esbuild
・Hotwire
・Session
・OAuth
・mkcert(SSL通信)
※私自身が未経験のため、説明に誤りがある可能性もございます。もし記事の内容に誤りや改善の余地があると感じられた場合は、お手数ですがご指摘いただければ幸いです。
作成物のイメージ
本記事で取り上げるアプリケーションの例は、「Sunkissing」という、日焼け止めの塗り直し通知アプリです。
LIFFを使ってLINEログインの実装もしております。
そのため、LINEログイン機能の実装を検討している方にもこちらのハンズオンは役に立つと思います。
本アプリのURLをLINEのトーク画面に送り、スマートフォンのLINEアプリから開いてみてください。PCよりもスマートフォンのLINEアプリから開いた方が、よりスムーズに動作するので是非お試しください。
今回のハンズオンのコードはこちらです。
https://github.com/mayuyuyuyunn/liff_sample_app
使用技術
Rails 7.0.4
ruby 3.1.2
Nodejs v20.3.1
LIFF(LINE Front-end Framework) v2.22.2
mkcert v1.4.4
LIFFとは
LIFFは、LINE Front-end Frameworkの頭文字を取ったものです。
LINE Front-end Framework(LIFF)は、LINEが提供するウェブアプリのプラットフォームです。このプラットフォームで動作するウェブアプリを、LIFFアプリと呼びます。
LIFFとはLINEアプリ上で動作するブラウザのことです。
LINEのトーク画面でURLを開くと、ChromeやSafariなどの外部ブラウザが開きますが、LIFFアプリのURLを開くと、LINEアプリ内部でブラウザが開きます。
またLIFFアプリは、他のブラウザで使用することもでき、登録しているメールアドレスやユーザーIDなど、LINEの情報を取得できるアプリとなります。
LIFFを使用する主なメリットは以下の3つです:
- LINEログインが使用できる
- LINEのトーク画面からLIFFアプリを開くと、初回を除いて自動的にログイン処理が行われる
- ユーザーID、友だち情報、アイコン写真など、LINEの情報を利用できる
LINEログインとは
無料で利用できるLINEアカウントを使用したソーシャルログインサービスです。
初回登録時にユーザー名やパスワードを考えて入力する手間がないため、ストレスフリーです。
詳細な情報はLINEログインの概要をご覧ください。
準備編
Railsプロジェクト作成
Railsの7系で作成しておきます。
$ mkdir liff_sample_app
$ cd liff_sample_app
$ rails _7.0.4_ new . --javasctipt=esbuild --skip-hotwire --css=bootstrap
Rails newのオプションについて説明します。(分かる方は飛ばしてください。)
-
--javascript=esbuild
JavaScriptのオプションで、esbuildを指定しています。 -
--skip-hotwire
Rails 7からデフォルトとなったフレームワーク、Hotwireに関するオプションです。Hotwireを使うと、JavaScriptを書かなくてもSPAのようなページを作成できます。今回のアプリでは利用しないのでスキップします。
今後開発をする中で、意図する挙動をしない場合は、Hotwireが原因の可能性もあります。後々開発で助かることもあるかもしれないので、頭の片隅に入れておきましょう。 -
--css=bootstrap
CSSのフレームワークとしてBootstrapを指定します。Bootstrapを導入することで、簡単に見た目を整えることができます。
mkcertの導入
ローカル開発環境でSSL/TLS証明書を作成するためのツール、mkcertを導入します。
ローカルサーバーを起動するときのURLは通常http://localhost:3000
となりますが、LINE DevelopersコンソールではコールバックURLの指定にhttp
は受け入れられません。
したがって、LIFF開発ではURLをhttps
にする必要があります。
mkcertのインストールをします。今回は、Homebrewで入れていきます。
$ brew install mkcert
$ mkcert -install
mkcertを使用して、SSL証明書を発行するための証明証を作成します。
$ mkcert localhost
localhost-key.pem
とlocalhost.pem
という2つのファイルが生成されたかと思います。
次に、config
ディレクトリ内にcerts
ディレクトリを作成し、生成した2つのファイルを移動します。
これらのファイルはGitHubにアップロードしないように、.gitignore
に/config/certs/*
を追記してください。
次に、config/puma.rb
の設定を行います。
ここでは3000番のポートで起動する記述port ENV.fetch("PORT") { 3000 }
をコメントアウトし、 mkcertで作成したSSL証明書を指定します。
# port ENV.fetch("PORT") { 3000 } ←元々記載があるのでコメントアウトする
ssl_bind "0.0.0.0", "3000", {
cert: "config/certs/localhost.pem",
key: "config/certs/localhost-key.pem"
}
これでローカルの開発環境がhttpsで起動できるようになりました。
modelとテーブルの作成
次に、Userの情報にline_user_id
を設定します。
通常のユーザー認証ではname
とpassword
を組み合わせて使用しますが、LINEログインを使用する場合はINEが提供する一意のuser_id
を取得して利用することができます。
$ bundle exec rails g model User line_user_id:string
マイグレーションファイルを以下のように設定します。ここではnullと重複を許容しないように制約を設けます。
class CreateUsers < ActiveRecord::Migration[7.0]
def change
create_table :users do |t|
t.string :line_user_id, null: false, unique: true
t.timestamps
end
end
end
マイグレーションを行います。
$ bundle exec rails db:migrate
マイグレーションが完了したら、同じようにモデルにもバリデーションをかけましょう。
class User < ApplicationRecord
validates :line_user_id, presence: true, uniqueness: true
end
controllerとviewの作成
Userに関するコントローラーとviewを作成します。
今回はユーザー作成とログインに関する機能のみ作成するのでnew createアクションを作成します。
$ bin/rails g controller users new create
ルーティングは下記の通りです。
Rails.application.routes.draw do
resource :user, only: %i[new create]
end
ApplicationControllerにログイン関係のヘルパーメソッドを作成していきます。
sessionはログイン機能などで使われるステートフルな通信を保つための仕組みですね。
突然session[:user_id]
が出てきて少し困惑する方もいるかと思いますが、session[:user_id]
の値を取得できれば、current_userがわかるというイメージがあればOKです。
class ApplicationController < ActionController::Base
helper_method :current_user
helper_method :login_required
helper_method :logged_in?
private
def current_user
# @current_userがnilでsession[:user_id]に値が入っている場合、ユーザーを持ってくる
@current_user ||= User.find(session[:user_id]) if session[:user_id]
end
def login_required
# ログインしていない(current_userが存在しない場合)root_pathに飛ばす
redirect_to root_path unless current_user
end
def logged_in?
!current_user.nil?
end
end
ログイン前後で見た目を分けたいのでstatic_pages
コントローラーと該当するページを作成します。
$ bundle exec rails g controller StaticPages top before_login after_login
class StaticPagesController < ApplicationController
def top
if current_user.nil?
render :before_login
else
render :after_login
end
end
def before_login; end
def after_login
login_required
end
end
Rails.application.routes.draw do
root 'static_pages#top'
get '/after_login', to: 'static_pages#after_login'
resource :user, only: %i[new create]
end
before_loginとafter_loginのviewファイルを書きます。
<div class="container">
<div class="jumbotron">
<h1 class="p-3 mb-2 bg-primary text-white">ログイン前のページです</h1>
<p>This is the homepage of my awesome website.</p>
<%= link_to '(LINE)ユーザー登録・ログイン', new_user_path, class: 'btn btn-success btn-lg' %>
</div>
</div>
<div class="container">
<div class="jumbotron">
<h1 class="p-3 mb-2 bg-danger text-white">ログイン後のページです</h1>
<p>This is the homepage of my awesome website.</p>
</div>
</div>
$ bin/dev
でサーバーを起動して、https://localhost:3000/
にアクセスしてみてください。
before_login
の画面がでます。「ユーザー登録・ログイン」ボタンをクリックしてhttps://localhost:3000/user/new
に遷移してればOKです。
確認できたら、ctrl + c
でサーバーを止めておいてください。
下準備編、次がラストです!
LIFFの処理はJavaScriptのファイルに書くので、JSファイルを作成していきます。
app/javascript/new.js
を作成してください。
デバックのために、console.log('new');
と書いておいてください。
console.log('new');
new.js
をusers/new.html.erb
で読み込ませます。
<p>Loading・・・</p>
<p>※時間がかかることがございます。</p>
<%= javascript_include_tag "new", "data-turbo-track": "reload", defer: true %>
再度https://localhost:3000/
にアクセスして、ボタンを押すと
https://localhost:3000/user/new
にアクセスできるか確認してください。
検証ツールでコンソールを開いて、下記のようにnew
の文字が出力されていればOKです。
LINE Developersの設定編
LINE Developersのページを開いて設定していきます。
以下のURLにアクセスし、普段ご自身が使っているアカウントでログインしてください。
コンソール(ホーム)からプロバイダを作成します。
名前は任意ですが、今回は「LIFFサンプル」と命名しておきます。
左側のメニューから「LINEログイン」をクリックして、チャネルを作成します。
チャネルの種類では「LINEログイン」、プロバイダでは先ほど作成した「LIFFサンプル」、そしてアプリタイプは「Webタイプ」 を選んでください。他の必要な項目はお好きに設定し、契約内容に同意できたら作成ボタンを押してください。
チャネル基本設定の一番上にある「チャネルID」をメモしておきます。このIDは後で使用します。
CHANNNEL_ID="チャネルIDの値"
次に、チャネル基本設定の隣のタブ「LINEログイン設定」をクリックし、LINEログインを使用できるように設定します。
コールバックURLにはhttps://localhost:3000/user/new
を入力してください。
さらに隣のタブで「LIFFアプリ」を追加します。
下記の画像を参考にして入力してください。エンドポイントURLはhttps://localhost:3000/user/new
と設定してください。
作成すると、一番上にLIFF_IDが表示されます。この値も後で使用するため控えておいてください。
CHANNNEL_ID="チャネルIDの値"
LIFF_ID="LIFF IDの値"
注意
この2つの値はGitHubなどにあげないように注意してください。
.envなど環境変数を用いてください。
RailsとJavaScriptのコード編
new.js
にLIFFを利用したコードを書いていきますが、その前にLIFFの仕組みについて簡単に説明します。
詳しい仕組みは下記の公式のシーケンス図なので、いつでも確認できるようにしておきましょう。
1.LIFFで作成されたアプリのURLを開く
2.LIFF SDKにアクセスして、LIFFの初期化とログイン処理を行う
3.LINE PlatformにアクセスしてLINEログイン処理をする
4.成功した場合、LIFFSDKにID tokenをくださいとリクエストが投げることができる
5.無事に取得できたら、ID tokenと一緒にLINE Platformにアクセスする
6.今回使用したいuser_IDだったり、ユーザー名、アイコン、登録しているメールアドレスなどの情報が取得できる
という仕組みのようです。
矢印が複数あり複雑に見えますが、赤い丸で囲ってあるゴール部分から説明していきます。
ゴールは、自分のサーバー(今回ならRails)からID token
を含むリクエストをLINEプラットフォームに送信し、user_id
やemail
などの情報を取得することです。
URLにoauth2
とあるように、ここではOAuth認証
を利用しています。悪意のあるリクエストを防ぐため、事前にトークンを発行し、そのトークンを添えてサーバーに情報送信の許可を得ます。
OAuthについては以下の記事を参考にしてください。
このプロセスではユーザー、作成したLIFFアプリ、LIFF SDK、アプリケーションサーバー、LINEプラットフォームの5つの要素が登場します。
SDKとはSoftware Development Kitの略称で、LIFF SDKはLIFF開発を簡単に行うために用意されたツールセットです。
詳細に知りたい方は、下記公式をみてください。
まず、LIFF SDKを使用するために、scriptタグで読み込みをします。
下記のコードを記載することで、liff.init
などLIFFで用意されているメソッドを使えるようになります。
application.html.erb
にあるbodyタグの中にLIFF SDKを読み込むためのscriptタグ追加してください。
<body>
<%= yield %>
<script charset="utf-8" src="https://static.line-scdn.net/liff/edge/2/sdk.js"></script>
</body>
続いてJavaScriptでコーディングします。
ここで先ほどLINE Developers編で作成したLIFF_ID
を利用します。
// DOMが読み込まれたら処理が走る
document.addEventListener('DOMContentLoaded', () => {
// csrf-tokenを取得
const token = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
// LIFF_ID を定数定義
const LIFF_ID = "自身のLIFF_IDをコピペする";
// LIFF_IDを使ってLIFFの初期化
liff
.init({
liffId: LIFF_ID,
// 他のブラウザで開いたときは初期化と一緒にログインもさせるオプション
withLoginOnExternalBrowser: true
})
// 初期化後の処理の設定
liff
.ready.then(() => {
// 初期化によって取得できるidtokenの定義
const idToken = liff.getIDToken()
// bodyにパラメーターの設定
const body =`idToken=${idToken}`
// リクエスト内容の定義
const request = new Request('/user', {
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
'X-CSRF-Token': token
},
method: 'POST',
body: body
});
// リクエストを送る
fetch(request)
// jsonでレスポンスからデータを取得して/after_loginに遷移する
.then(response => response.json())
.then(data => {
data_id = data
})
.then(() => {
window.location = '/after_login'
})
})
})
liffの構文について詳しく知りたい方は、下記リファレンスを確認してください。
続けて、Userコントローラーです。
LINE Developers編で作成したCHANNNEL_ID
を入れるのを忘れないようにしてください。
class UsersController < ApplicationController
require 'net/http'
require 'uri'
def new
if current_user
redirect_to after_login_path
end
end
def create
id_token = params[:idToken]
channel_id = "保存したチャネルIDを入れる"
res = Net::HTTP.post_form(URI.parse('https://api.line.me/oauth2/v2.1/verify'), { 'id_token' => id_token, 'client_id' => channel_id })
line_user_id = JSON.parse(res.body)['sub']
user = User.find_by(line_user_id:)
if user.nil?
user = User.create(line_user_id:)
elsif (session[:user_id] = user.id)
render json: user
end
end
end
create
アクションは先ほどのシーケンス図で赤い印でゴール部分で説明した部分です。自分のサーバーからLINEプラットフォームにID token
を引っ提げてリクエストを送っています。
id_token = params[:idToken]
でOAuth認証に必要なID token
を取得しているのですが、これは先ほどnew.js
に書いたコードのおかげで持ってこれています。bodyに情報を入れてリクエストをおくりました。どこの部分か分からない方は、少し戻ってnew.js
のコードを見てください。
net/httpライブラリとurlライブラリを使用して、LineプラットフォームにUser情報を取得するためのリクエストを投げています。
最後に、line_user_idを取得して、初登録の方はline_user_idを保存、すでに登録している方はsession[:user_id]に取得したline_user_idを入れてログイン処理を行っています。
再度、サーバーを起動して新規登録・ログインをしてみましょう!
LINEログインの認証画面に遷移し、ソーシャルログインができるかとおもいます。
最後に
お疲れ様でした!!!
これにて、LIFFを用いたLINEログインのハンズオンは完了です。
LINEは現在日本でいちばん使われているコミュニケーションツールのため、
通知系のアプリを作りたい方はLINEを使用して開発するのが便利で良いのかなと思います。
今回LIFFを使用して個人開発をしてみて、Hotwire、セッション、oAuth、SSLなど様々なことを学習するきっかけになりました。
ハンズオンをしてみて、分からないところがあれば調べて復習するといい勉強になると思うのでぜひやってみてください。
この記事が、個人開発をする上での一助になれば幸いです。
最後までお付き合いいただきありがとうございました。
個人開発のアプリ、是非使ってみてください〜
https://www.sunkissing.net/