Firebase Authenticationを実プロダクトに採用しているプロダクト多いんじゃないでしょうか。 メールアドレスはもちろん、TwitterやGitHubと言ったエンジニア各位が持ってそうなアカウントを用いたFirebaseのアカウントの発行もサポートしています。
そんなFirebase Authenticationですが、日本で多く使われているLINEみたいなサービスは標準でサポートされていません。 今回はそういったサポートされていないOpenID Connect対応なサービスを使ったFirebaseアカウントの作成およびログインをやっていこうと思います。
完成しているプロジェクトは
こちらになります。 コード見ればわかるぜという方はこちらを参考にして下さい。
記事を書き始めたらちょっと大変だったので連載物にします!!!!!すぐ次のやつ書きます!!!!!
使用したサービス
- Firebase Authentication
- Firebase Firestore
- Azure Functions
実装やっていく
LINEの公式ドキュメントを見ながら実装を進めていきましょう。
https://developers.line.biz/ja/docs/line-login/web/integrate-line-login/
こちらのドキュメントの「始める前に」と「チャネルを設定する」は既に完了している状態と仮定して進めていきます。
LINEログインに直接は関わりませんが、今回Firebase Authenticationも使うのでFirebaseのプロジェクトも作っていきます。
Firebaseのプロジェクト作る
Firebase Authenticationを使うのでFirebaseのプロジェクトを作りましょう。 LINEログインのURLを生成する際に使用するStateやNonceと言った値をユーザと紐付けるために今回はFirestoreを使用してみます。 そのためFirebaseのプロジェクトを作った際、Firestoreも使用できるようにしておきましょう。
またFirestoreはFirebaseのユーザと紐付けた形で使用します。 FirebaseのアカウントをLINEログインで作成するのにFirebaseのアカウントを作るとは…みたいな卵が先か鶏が先かみたいなことになります。
その問題を解消するためにFirebase Authenticationの匿名認証を今回は使用してみます。
https://firebase.google.com/docs/auth/?hl=ja
匿名認証の説明を引用してみます。
一時的な匿名アカウントを作成することで、ユーザーにログインを要求することなく認証できる機能を使用します。ユーザーが後から登録することにした場合は、匿名アカウントを通常のアカウントにアップグレードして、ユーザーが前回終了したところから操作を続行できるようにすることができます。
ユーザにアカウントの作成およびログインを意識させずにFirebaseアカウントを作成しやすそう、またアカウントがあるのでFirestoreを使いやすいと言ったメリットがあります。 ということで、Firebase Authenticationのログイン設定で匿名認証を有効にしておきましょう。
ログインのためのURLの作成
LINEの公式ドキュメントのログインフローでの(1)に該当する部分を実装し、(2)ます。
生成するURLに必須のパラメータは以下ドキュメントで確認します。
この必須パラメータで予め固定できるものは response_type
, client_id
, redirect_uri
, scope
です。
ユーザ(リクエスト?)固有にする必要があるのが state
パラメータです。
この state
パラメータはアプリケーション側で作っていきます。
実際のコードはこちらです。
from token in ParseAuthorizationToken(req) // 匿名認証のFirebase AuthのTokenを取得 let authTemp = AuthTemporary.GenerateRandomAuthTemporary() // Randomのstateを生成する from _ in TryAsync(() => _authTempClient.StoreAuthTemporary(token.Uid, authTemp).ToUnit()) // Firebaseのアカウントに紐づけてstateをFirestoreに保存する .ToEither(e => e.Exception.IfNone(new Exception(e.Message))) let url = _lineService.GetAuthorizeRequestURL(authTemp) // stateの値を埋め込んでURLを生成する select url
流れとしては本当にシンプルですね。 詳細の実装はコードをご覧ください。
ここで必要なのはFirebaseユーザとここで生成したstateの値を紐付けて保存する、ただこれだけです。
あとはこのURLをユーザに踏んでもらいます。
フロントの実装はこんな感じ。
Firebase Authenticationの匿名認証をして、そのTokenをアプリケーション側に送り生成されたURLに遷移するみたいなことを上記のコードでは行っています。
コールバックから情報を受け取る
ここではドキュメントの(3)と(4)を実装していきます。
ユーザが権限に同意した場合、コールバックURLにユーザがリダイレクトされます。 このコールバックされたページのクエリパラメータを用いてアプリケーション側でアクセストークンを取得していきます。
フロント側から code
と state
と friendship_status_changed
をアプリケーションに送信します。
送信側のコードは
ただ単にHeaderをパースして送ってるだけです。簡単。
アプリケーション側は
from token in ParseAuthorizationToken(req) // 匿名認証のFirebase AuthのTokenを取得 from requestBody in TryAsync(() => { using var sr = new StreamReader(req.Body); return sr.ReadToEndAsync(); }).ToEither(e => e.Exception.IfNone(new Exception(e.Message))) from json in Try(() => System.Text.Json.JsonSerializer.Deserialize<LineTokenRequest>(requestBody, new System.Text.Json.JsonSerializerOptions { PropertyNameCaseInsensitive = true })) // リクエストパラメータのParse .ToEither((e) => new Exception("invalid json object", e)).ToAsync() from authTemp in TryAsync(() => _authTempClient.RestoreAuthTemporary(token.Uid)).ToEither(e => e.Exception.IfNone(new Exception(e.Message))) // Firebaseのアカウントに紐付いたstateをFirestoreから引っ張ってくる from _ in (authTemp.State == json.State) // stateがアプリケーション側で作られたものとリクエストパラメータと一致するかの検証 ? RightAsync<Exception, Unit>(Unit.Default) : LeftAsync<Exception, Unit>(new Exception("State is not matched")) from lineIdentity in TryAsync(() => _lineService.GetLineIdentify(json.Code, authTemp.Nonce)) // リクエストパラメータの `code` パラメータを元にLINEのアクセストークンを取得 .ToEither(e => e.Exception.IfNone(new Exception(e.Message)))
の流れで行っていきます。
ここで重要なのはアプリケーション側で生成された state
パラメータが一致しているかの検証と、code
パラメータからLINEのアクセストークンを取得するところです。
ここではアクセストークンを生成する部分を少し紹介します。
ここで使用されている _lineService.GetLineIdentify
の実装は以下のとおりです。
内容としては
https://api.line.me/oauth2/v2.1/token
に対してユーザから来たcode
パラメータとその他必要なパラメータを付与しリクエストを送ってアクセストークンやユーザの情報を取得する- (Optionalだけど)
https://api.line.me/oauth2/v2.1/verify
に対して 1. で手に入れたアクセストークンを送信してtokenの検証を行う - で手に入れたアクセストークン(JWT)をパースして、LINEのユーザIDを取得する
を行っています。
1のアクセストークン生成に必要なパラメータは
https://developers.line.biz/ja/docs/line-login/web/integrate-line-login/#spy-issue-access-token
を、
2のアクセストークンの検証に必要なパラメータに関しては
https://developers.line.biz/ja/docs/social-api/managing-access-tokens/#spy-verify-access-token
を参照して下さい。
以降の処理では1. で手に入れたLINEのユーザIDを使用していきます。
Custom Tokenでログイン
さて……ここらへんは次の記事で(一番見たい部分ではあるけど)
ということで一旦ここまでで〆ます