MUSHIKAGO APPS MEMO

Firebase (iOS) : LINEログイン認証に挑戦

Facebookログイン、Twitterログインを使った認証は、あらかじめFirebase側に用意されたログイン方法なのでわりとシンプルに利用できたのですが、ここに用意されていないログイン方法の「LINE Login」を使ったFirebaseの認証はそうはいかなそうです。はっきり言ってややこしいです。最終的にはなんとか成功しましたが、すでにログインしている状態でそのFIRUserに対して、LINEログインでも同じユーザにログインできるよう紐付ける「link」機能については、断念しました(カスタムログインにリンク用のメソッドが用意されてないのでもともと無理ぽ?)。

追記(2020/10/21)
LINEログインの検証エンドポイントがv2.1になったため、参考資料にあるサンプルが動作しなくなっていました。こちらのMEMOもご参考に↓。

だいぶ前にiPhone用のFirebaseアプリにLINEログイン機能を追加することに挑戦していたのですが、LINEログイン側がバージョンア...

とりあえず、なんとか成功したLINEログイン単体でのFirebase認証についてMEMOしておきます。

スポンサーリンク

参考資料

まず、参考としたサイトやドキュメントをリストしておきます。

Firebase Authentication を使って LINE Login を導入する方法について解説します。

↑もっとも参考にさせていただいたのがこちら。Google公式ブログの翻訳記事です。こちらのサンプルをおおよそ利用させていただきました。が、SDKのバージョンがひとつ前のものである点と言語がSwiftではないので、その辺を修正しました。

↑そのサンプルコードです。随時アップデートされていますが、現時点でLINE SDKはひとつ前のLineAdapter用に書かれています。でも、やるべき流れはほとんど同じなのでとても参考になります。LINE以外のものもあるようです。

↑LINEログインの公式ドキュメント。LINEログインに成功させるまでの流れはこちらを参考にすべしです。最新の情報が得られます。2017/3/22にCocoaPods対応したようですが、その辺のセットアップ方法からわかりやすく書かれています。

↑Firebaseの公式ドキュメント。

普通の JavaScript も jQuery もまともに書けないけど、はじめての Web アプリを Node.js でつくってみるという奮闘記。 環境つくるだけなのに何も分からなすぎてハマりすぎて、この一連の流れだけで丸 2 日潰れるという大惨事だったので、ちゃんとブログに残しておく。 Node.js のインストール...

↑LINEログインで認証を行う際、Node.jsの動作する環境が必要となるのですが、とりあえず、最近よく使うので、herokuを選択しました。そのherokuに対してNode.js + Expressをセットアップする手順が詳しく書かれています。

↑LINE BUSINESS CENTER (日本語)

サンプルについて

まず、上記参考資料のGoogle記事の最後にリンクされているサンプルの中身を確認してみます。HUDViewというのは通信中を示すグルグルで、LoginControllerというのはビューコントローラーのクラスなので、こうしたごちゃごちゃしたものを無視して、重要そうなのは「LineAuthManager.m」ですね。そして、このサンプルではサーバーサイドのNode.jsを使っており、そのソースが「server」フォルダに一式入っていますので、これはとりあえずそっくりそのまま使ってみます。

また、これらサンプルがObjective-Cで書かれているのと、SDKが現時点の最新のものではなく、バージョン3.2.2のLineAdapterと呼ばれているものを使う例になっているため、ここでは、現時点で最新のLineSDK4.0.2をCocoaPodsで組み込む形にし、言語もSwiftにして試してみようと思います。

Line developersの登録とLineSDKの組み込み

に手順が書かれています。英語ですが、スクリーンショットも多く、おおよそ手順通りに進めることができると思います。

流れとしては、Create a business account and Channel でアカウントやチャンネルを作成し、Technical Configuration を行うといった感じです。

LINE BUSINESS CENTERでアカウントの作成

にてビジネスアカウントを作成して、サービス>LINE Login>「LINE Loginを始める」でアカウントを作成します。

申し込みタイプというのは、「NATIVE_APP」を選択。

「LINE Developersへ」を。

Channel IDを取得

ここでChannel IDを取得できます。

Technical configurationの設定

iOS Bundle IDとiOS Schemeを設定します。iOS Schemeは、「line3rdp.」にiOS Bundle IDをつなげたものを記述しておきます。

LINE SDKのセットアップ

ドキュメントでは、「Using the LINE SDK for iOS」部分です。CocoaPodsで最新のLineSDK 4.0.2をセットアップしときます。Podfileに以下を追記して、ターミナルで pod update ですね。

pod 'LineSDK', '~> 4.0.2' 

公式サンプルで動作確認

ここでいったん自分のアプリではなく、公式アプリで正しくLINE Loginが可能かどうかを確認してみましょう。(ここで確認できるのは、LINEログイン部分までで、そのログインを利用したFirebase認証部分は、当然ながらこのサンプルには入っていません。)

A starter application that demonstrates how to use LINE SDK for iOS. - line/line-sdk-starter-ios-v2

からZipでいいのでダウンロードします。「LineSDKStarterSwift」内に Podfile があってまだセットアップされてませんので、ターミナルでそのディレクトリまで移動して、 pod update でLineSDKをインストールし、LineSDKStarterSwift.xcworkspaceを開きます。このテンプレートは、info.plistに「LineSDKConfig」があって、そこに「ChannelID」を書き込むようになっています。上記のLINE DevelopersのBasic Informationにあった Channel IDをここへコピペします。

また、Technical configurationで設定したiOS Bundle IDでなければなりませんので一致させ、Team部分も赤文字になってる場合は自分のアカウントにしておきましょう。

「A2A Login」と「Web Login」とだけ表示されるサンプルです。iOSシミュレータで実行すると「Web Login」の方は試せると思います。「A2A Login」はLINEアプリで認証するので実機で。

この実験が成功したなら、LINE Developersの方の設定等は問題ないということになると思います。このサンプルアプリが後で邪魔になると面倒そうなので、実験に成功したら、ログアウトしてアプリを削除しておきましょう。また実機のLINEアプリでは、「設定>アカウント>連動アプリ>(自分のアプリ)>アプリ連動解除」で先ほどサンプルで承認したアプリ連動を解除できます。

自前の検査サーバーの構築

では次に何をすべきなのか。改めて上記参考資料のGoogle記事、および、Google記事のサンプルを見てみます。よくみると

  1. Step 1: Communication with LINE SDK
  2. Step 2: Communication with own validation server
  3. Step 3: Communication with Firebase Auth SDK

とコード内にもコメントがあります。上記までの公式サンプルの実験でStep1までは成功することが確認できてます。次に用意すべきは、「Communication with own validation server」部分です。記事内の記述では、

ステップ 2: LINE アクセス トークンを自分のサーバーに送信し、LINE 認証サーバーを使ってそれを検証します。トークンが有効である場合、ユーザーに対応する Firebase カスタム認証トークンを作成し、ユーザーの端末に返します。

とのこと。うーむ、ややこしいですねぇ。負けずにやってみます。前述の「サンプルについて」でも書きましたが、このサーバーサイドのコードは、このサンプルでそっくりそのまま使わせてもらっちゃいます。問題は、サーバー環境ですね。

Heroku上にNode.js + Expressのセットアップ

ここで最近よく使ってる Heroku を利用させていただきます。(Herokuでなくとも、Nodo.jsが動作するところならどこでもありかと思います)

記事内で、

LINE アクセス トークンを検証し、ユーザーに対応する Firebase カスタム認証トークンを生成するには、サーバーが必要になります。Firebase Node.js Server SDKExpress ウェブサーバーを使うと、シンプルなサーバーを構築できます。

とありますので、Express環境をHeroku上に用意します。これについては、

普通の JavaScript も jQuery もまともに書けないけど、はじめての Web アプリを Node.js でつくってみるという奮闘記。 環境つくるだけなのに何も分からなすぎてハマりすぎて、この一連の流れだけで丸 2 日潰れるという大惨事だったので、ちゃんとブログに残しておく。 Node.js のインストール...

に手順がわかりやすく書かれていました。この手順通りにとりあえず、Expressのセットアップまでのログがこんな感じ。ハイライトしてるところが打ち込んだコマンドです。

source code by gist.

とりあえず、ここまでやって heroku上のアプリをブラウザで開くとExpressの初期ページが開かれて、Node.js等が正しく動作していることが確認できます。

heroku上で動いた時点でソースをSourceTree管理にしときます(任意)。ターミナルでローカルリポジトリやリモートの紐付けなどは行っているので、既存のディレクトリを追加するだけです。

サンプルコードを上書き

サンプルのコードを自前のExpressアプリに思い切って上書きしちゃいます。

Firebaseコンソール「プロジェクトの設定>サービスアカウント>Firebase Admin SDK>新しい秘密鍵を生成」で生成した秘密鍵(.json)を「service-account.json」というファイル名でこのフォルダに保存。

もうひとつ「config.json」内でLINE developersで取得したchannelIDを書き込みます。

ここまでサンプルコードを修正したら、「node app.js」を実行してみます。すると何かモジュールが足りないというエラーが発生すると思うので、必要なものをインストールしていきます。

npm install --save request
npm install --save request-promise
npm install --save firebase-admin

この3つインストールしたら「node app.js」でもエラーなく動作しました。http://localhost:8080 を開くと「Server is up and running!」と表示されました。

ローカルで成功したので、いよいよHerokuへプッシュします。Herokuへはプッシュすると同時にデプロイされるので、heroku/masterへのプッシュ作業が成功に終わればデプロイもうまくいったと思われます。

サンプルコードでLINEログイン+Firebase認証

もうこの辺でヘトヘトな感じだと思いますが、最終段階まであと少しです。まずは、うまく動作するはずのGoogle記事のサンプルを自分のアプリのバンドルIDに置き換えて動作成功するか実験してみます。これがうまくいったら、最後は、このサンプルの必要な箇所だけ抜き出して、自分のSwiftアプリに移植するという感じです。がんばってみましょう。

Google記事のサンプルをZipダウンロードでいいので落とします。Zip内の「Line>iOS>LINELoginDemo」がサンプルです。このサンプルもターミナルで移動して、pod update しましょう。Podfileは用意されています。

次にバンドルIDとTeamも自分のものに書き換えます。

そして、このサンプルに足りていないファイルを追加していきます。ひとつは、Firebaseコンソールから「GoogleService-Info.plist」を落としてきます。

次にLineAdapterと書かれている少し前のLINE SDKです。このサンプルではこちらがつかわれているので手動で配置します。

どちらともXcodeにドラッグアンドドロップで読み込みますが、その際に「copy items if needed」にチェックしましょう。参照先不明で赤くなっていたファイル名が黒になると思います。(読み込んだことで重複するのでどちらかは参照を削除します)

次にふたつ修正する箇所があります。ひとつは、「Configs.h」。この中の

static NSString *const kValidationServerDomain = @"<your_line_token_verification_server>";

の部分を上記で作成したherokuサーバのURLに書き換えます。「https://xxxxx.herokuapp.com」のようなURLです。次に「LineAdapter.plist」の「ChannelId」の値にLINE Developersで取得したChannel IDを書き込みます。

ここまでやったらiOSシミュレータで実行してみます。

LINEアカウントのサムネが表示されたら、大成功!しかし、実機で確認すると「Unable to login using LINE」と出ました。アプリで認証する場合、もいっちょ修正する箇所がありました。以下のように修正すると動作すると思います。(これまでにテストしてきた同じバンドルIDのアプリは一度キレイに掃除してからテストしたほうがいいです)

LINEログインだけのテストとは違い、こちらのサンプルでログイン認証が成功すると、FirebaseコンソールのAuthenticationのリストにも「line:〜」というuidのユーザが作成されます。つまり、ようやくこのMEMOで目的としているLINEログインを使ったFirebase認証が正しく行われ、FIRUserが作成されたということです!

ここまできたらようやく最終段階、このサンプルの動作をSwiftに書き換えて自前アプリに実装です。

サンプルをSwiftにして自前アプリに移植

この記事サンプルをSwiftに書き直したものをクラスファイル化してGitHubにアップしました。

Contribute to mushikago/LineLoginManager development by creating an account on GitHub.

「LineLoginManager.swift」がそれです。「HUDView.swift」というのは、待ち状態を示すグルグルです。これもサンプルにならって作っておきました。Zipやクローンでローカルに上記2つのファイルを落として、自前アプリにドラッグ&ドロップします。

「copy items if needed」をオンに。

SDKは、サンプルとは違い、CocoaPodsでインストールした最新のLineSDKを使う形になっています。また、サンプルでは「GTMHTTPFetcher」というのを使っていますが、これもよく似た「GTMSessionFetcher」の置き換えています。

簡単に動作の説明を書くと、initialize時に

LineSDKLogin.sharedInstance().delegate = self

としていますので、LineSDKLoginが実行され、LINEログイン認証が終わって呼び出されるのが、この LineLoginManager の

func didLogin(_ login: LineSDKLogin, credential: LineSDKCredential?, profile: LineSDKProfile?, error: Error?) {

となります。そして、LindSDKから得たアクセストークンを自前の検査サーバに送るのが「requestFirebaseAuthTokenWithLINEAccessToken」関数部分。この時にサーバーから結果が返ってくるまで待つ(herokuが眠ってるとそこそこ時間がかかります)ので、HUDViewを使ってグルグル回してます。無事に結果が戻ってきたら、その firebase_token をパラメータとして「authenticateWithFirebaseToken」関数へ。この関数では、NotificationCenter を使って、「doAuthenticateWithFirebaseToken」と定義されたものを呼び出しますが、その際にこの引数で受け取った firebase_token を userInfo に入れて渡します。

LineLoginManagerの実際の使い方

まず、ここで使っている「GTMSessionFetcher」はLineSDKインストール時にすでにインストールされているようなのでそのままで。そして「ChannelID」と「ValidationServerDomain」の設定は、info.plistに「LineSDKConfig」というDictionary型を作ってその中に入れて読ませるようにしました。

この状態にしておいて、あとは「LINE Loginボタン」を設置します。ボタンを配置するUIViewControllerの viewDidLoad などで、

LineLoginManager.ins.initialize(_self: self)

と書いてLineLoginManagerを初期化しておきます。selfをパラメータを渡しているのは、HUDViewが乗っかるUIViewControllerにするためです。あとは、Firebase Tokenを受け取って、実際に

FIRAuth.auth()?.signIn(withCustomToken:

とカスタムトークンで signIn を行う「doAuthenticateWithFirebaseToken」を記述し、NotificationCenter.default.addObserver を使って「doAuthenticateWithFirebaseToken」が呼び出されたら、この fund doAuthenticateWithFirebaseToken を呼び出すように監視させます。あとは、LINEログインのボタンアクションを作って、「LineSDKLogin.sharedInstance().start()」を実行するように書きます(このコード上に import LineSDK が必要です)。この辺のコードはこんな感じです。

source code by gist.

AppDelegateでもやることがあります。 import LineSDK をしつつ、

func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
        if url.absoluteString.contains("line3rdp.") { //LINE
            return LineSDKLogin.sharedInstance().handleOpen(url)
        }
        return false
}

を加えます。そして、もうおなじみになってきましたが、info.plistの設定。「URL Schemes」に「line3rdp.$(PRODUCT_BUNDLE_IDENTIFIER)」を、そして「LSApplicationQueriesSchemes」には「lineauth」と「line3rdp.$(PRODUCT_BUNDLE_IDENTIFIER)」を。

ここまでやったら、最後に実機で確認してみます。

ついに!自前アプリでエラーなくFIRUserが取得できました!!!

最後、本当に地味ですが、ここでFIRUserが取得できたということは、LINEログインによってFirebase上で認証を行い、FIRUserを作成することに成功した、ということですので、あとは、ログイン状況にあわせてアイコンを用意したりと飾り付けを行えばOKなわけですね。