meepa | 子どもの本当の好きに出会う 課外活動マッチングサービス
meepaは「子どもの本当の好きに出会う」を目指して、幼稚園・保育園・学童などで子どもたちが様々な体験の機会を得られるように、園と課外活動提供者をマッチングするサービスです。
https://meepa.io/
こんにちは、Developerの松村です。
LINE Front-end Framework(LIFF)を使う機会があったので、導入方法や機能を紹介します。
弊社が開発している「meepa」は、「子どもの本当の好きに出会える課外活動マッチング」をコンセプトに、忙しい親御さん向けにチャットでお子さんが熱中できる習い事を提案してあげるサービスです。
もともとはLINE Messaging APIを使ったチャットBotで、LINEのトーク画面上だけで、レコメンドの受信から体験レッスンの予約まで完結できるサービスとして開発し、PoC検証を行ってきました。
PoC検証を進めていく過程で、LINEのトーク画面だけでは、操作性やユーザーに提示できる情報量に限界を感じ、一部機能をWebに切り出すことにしました。
その際にトーク画面から遷移したWebページ側で、ユーザー認証を行う必要があったため、LINE Front-end Framework(LIFF)を使って実現することにしました。
LINEが提供するウェブアプリのプラットフォームです。
LIFFを使うことで、LINEのユーザーIDやプロフィールをLINEプラットフォームから取得できるので、ユーザー情報を活用した機能を提供することができます。
また、ユーザーのトーク画面に直接メッセージを送信したりすることができます。
LINE Developersコンソールにログインし、「新規チャネル作成」ボタンからLINEログインのチャネルを作成ます。そのなかで、アプリタイプを選択するところがあるので、今回はウェブアプリを選択します。
チャネルを作成したら、「LINEログイン設定」、「LIFF」のタブでそれぞれ設定を完了します。
LIFFアプリの設定が完了すると、「LIFF ID」というものが発行されます。
フロントエンドのソースコードにフレームワークを読み込みます。
今回はyarnでインストールしていきます。
yarn add @line/liff
TypeScriptで実装する場合は、LIFF独自の型定義もインストールしておきます。
yarn add -D liff-type
そしてtsconfig.jsonに追加します
{
...中略...
"types": [
"liff-type"
]
}{
...中略...
"types": [
"liff-type"
]
}
そして、ページが読み込まれたら、作成したLIFF IDを使って初期化します。
import liff from '@line/liff'
liff
.init({
liffId: `作成したLIFF ID`
})
.then(() => {
// 以降、LIFF APIが使えるようになる
})import liff from '@line/liff'
liff
.init({
liffId: `作成したLIFF ID`
})
.then(() => {
// 以降、LIFF APIが使えるようになる
})
とすれば、LIFF APIが使えるようになります。
liff.login()でログイン処理を行います。
liff
.init({
liffId: `作成したLIFF ID`
})
.then(() => {
if (!liff.isLoggedIn()) {
liff.login();
}
})liff
.init({
liffId: `作成したLIFF ID`
})
.then(() => {
if (!liff.isLoggedIn()) {
liff.login();
}
})
LIFFでログイン機能を実装するメリットは、LINE内ブラウザでWebアプリを開いた際は、自動でログイン処理がされるため、ユーザーがID/Passwordの入力を行う必要がありません。
liff.getProfile()で、ユーザーのID、表示名、プロフィール画像といった、プロフィール情報を取得できます。
liff
.getProfile()
.then((profile) => {
const name = profile.displayName;
})liff
.getProfile()
.then((profile) => {
const name = profile.displayName;
})
LIFFアプリが開かれているトーク画面にメッセージを送信することができます。
sendMessagesに渡す引数はLINE Messaging APIと同様です。
liff
.sendMessages([
{
type: "text",
text: "Hello, World!",
},
])liff
.sendMessages([
{
type: "text",
text: "Hello, World!",
},
])
なお、このAPIを使用するには、chat_message.writeのScopeを選択する必要があります。
友だちやグループを選択する画面を表示し、選択した相手に、固定のメッセージを送信することができます。
この機能を使って、ユーザーから直接サービスを広めてもらったり、招待クーポンを発行する、といったこともできそうです。
if (liff.isApiAvailable("shareTargetPicker")) {
liff
.shareTargetPicker(
[
{
type: "text",
text: "Hello, World!",
},
],
{
isMultiple: true,
}
)
}if (liff.isApiAvailable("shareTargetPicker")) {
liff
.shareTargetPicker(
[
{
type: "text",
text: "Hello, World!",
},
],
{
isMultiple: true,
}
)
}
何れかの処理をサーバー側で行う場合、なりすましなど攻撃に対して脆弱になるため、フロントエンドで取得したユーザー情報をそのままサーバーに送ってはいけません。
サーバー側でユーザーのプロフィール情報を使う場合、フロントエンドからはアクセストークンのみを送信し、サーバー側でトークンの検証をすることで、安全にユーザーのプロフィール情報を取得することができます。
フロントエンド側では、liff.getAccessToken()でアクセストークンを取得し、APIのヘッダーで指定します。
const accessToken = liff.getAccessToken();
// APIのヘッダーでアクセストークンを渡す
axios.get("https://api...", {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
},
//...
});const accessToken = liff.getAccessToken();
// APIのヘッダーでアクセストークンを渡す
axios.get("https://api...", {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
},
//...
});
サーバー側では、受け取ったアクセストークンを
GET /oauth2/v2.1/verify(Access Token)でアクセストークンを検証し、有効なことが確認できたら、GET /v2/profileでユーザーのプロフィールを取得できます。
node.jsの場合はこうです。
// アクセストークンを検証
const res = await axios.get("https://api.line.me/oauth2/v2.1/verify", {
params: {
access_token: accesstoken
}
});
if (!res.error) {
// ユーザーのプロフィールを取得
const profile = await axios.get("https://api.line.mev2/profile", {
headers: {
Authorization: Bearer ${accesstoken}
}
})
}
// アクセストークンを検証
const res = await axios.get("https://api.line.me/oauth2/v2.1/verify", {
params: {
access_token: accesstoken
}
});
if (!res.error) {
// ユーザーのプロフィールを取得
const profile = await axios.get("https://api.line.mev2/profile", {
headers: {
Authorization: Bearer ${accesstoken}
}
})
}
サーバーにユーザー情報を渡す方法として、IDトークンを渡す方法もあります。(POST /oauth2/v2.1/verify(ID Token))
IDトークンとアクセストークンとでは、取得できる情報と、トークンの期限が異なります。
アクセストークンで取得できるユーザー情報は、
・ ID
・ 表示名
・ プロフィール画像
・ステータスメッセージ(ユーザーが設定している場合のみ)
です。
IDトークンで取得できるユーザー情報は、アクセストークンで取得できる3つに加えて、「emailアドレス」も取得できます。
アクセストークンの期限はログインから12時間後で、フロント側で再ログインすると更新されます。
対してIDトークンは、期限は1時間と短く、期限切れ後に再ログインしても更新されませんでした。
フロントエンドだけでログイン、プロフィール取得、トークへのメッセージ送信といったことが簡単にできるので、meepaのようにLINEと密接に関わるアプリでは非常に便利だと感じました。
ユーザーのログインの手間を省けるのもメリットです。
一方で、LINE以外のOAutuサービスも併用する場合は、棲み分けが面倒になるし使わないだろうな、というのが正直なところです。
今回は触れませんでしたが、個人的にはBluetoothプラグインを介してBLEデバイスとの連携ができるという点が気になっています。
現在はAndroidのみのサポートのようですが、IoTアプリケーションが簡単に作れてしまう素晴らしいものなのでは?という可能性を感じています。
LINE Front-end Framework(LIFF)をWebアプリに導入する方法をざっと紹介しました。
dotDでは、LINE APIをはじめ、世の中にオープンになっているテクノロジーを調査・検証しながら、自社のプロダクトに素早く反映していく活動をしていますが、まだまだエンジニアの手が足りません。
実験をしたり、プロトタイピングしながら、アイデアをカタチにしていく仲間を募集しています。カジュアル面談も歓迎しているので、興味を持ってくださった方はお気軽にご連絡ください!