シリアルコード認証(カスタム認証) - UnityでSDKなしでFirebaseを使う
Firebase Authenticationでは基本的な機能としてメールアドレスとパスワードによる認証、電話番号認証、OAuthを利用した認証などが用意されています。基本的な認証方式以外の方法(例えばIDとパスワードによる認証やシリアルコードによる認証など)はカスタム認証機能を使って作成する事ができます。
今回はシリアルコードを利用した認証の仕組みを作成する方法を解説していきます。
この投稿はUnityでSDKなしでFirebaseを使うの一部です。
途中で出てくるソースコードの全体は以下にあります。
Unity側:
Firebase側:
システムの構成
今回は以下の構成の認証システムを作成します。
シリアルコードとカスタムトークンの交換Functionの作成
はじめにFirebaseの各種設定とFirebase Functionの実装を行なっていきます。
IAM API の有効化
トークンに署名する際にIAM Service Account Credentials API
を利用するので、APIを以下のURLから有効化します。
カスタムトークン作成権限の設定
Firebase Functionsの実行時に使用されるアカウントにカスタムトークンの作成権限を付与します。
まず以下のURLからGCPのIAMのページに移動します。
名前がApp Engine default service account
となっているサービスアカウントのメンバーを編集
します。
サービスアカウントトークン作成者のロールを追加して保存します。
トークン発行Functionの作成
ローカルのFirebaseプロジェクトのfunctions
ディレクトリ配下にシリアルコードとカスタムトークンを交換する処理を実装していきます。
プロジェクトを作った際にサンプルコードのが書かれたindex.tsファイルが作成されていますが以下のコードに書き換えます。
将来的にfunctionを複数作成する際にfunctionごとにtsファイルを作成したいので、index.tsには直接処理を書かず他のファイルの処理が呼ばれるように実装しています。
import * as functions from "firebase-functions";
import * as express from "express";
import * as admin from "firebase-admin";
// eslint-disable-next-line @typescript-eslint/no-var-requires
const customAuth = require("./handlers/custom-auth");
admin.initializeApp();
const expressApp = express();
expressApp.get("/", customAuth.handler);
exports.customAuth = functions
.region("asia-northeast1").https.onRequest(expressApp);
トークンの交換処理本体は以下の実装になります。
以下の実装では、わかりやすさのためシリアルコードとユーザーIDはリテラルになっていますが、Firestoreにシリアルコードを持たせる実装のサンプルコードもGitHubのリポジトリで公開しています。
import * as express from "express";
import * as admin from "firebase-admin";
exports.handler = async (req: express.Request, res: express.Response) => {
const serialCode = "xxxx-yyyy-zzzz";
const uid = "uid-0001";
// Unity側からはURLクエリパラメーターのserialCodeにシリアルコードを設定してリクエストする
if (req.query.serialCode == serialCode) {
admin
.auth()
// ここでFirebase Authenticationにuidのユーザーが追加されて、サインイン用のトークンが返ってくる
.createCustomToken(uid)
.then((customToken) => {
// customTokenをJsonレスポンスとして返す
res.status(200).json({customToken: customToken});
})
.catch((error) => {
console.log("Error creating custom token: ", error);
res.status(500).json({message: "トークン作成失敗"});
});
} else {
res.status(500).json({message: "トークン作成失敗"});
}
};
コードができたら、firebase deploy --only functions
コマンドを実行してデプロイします。
Functionのデプロイの確認
Firebaseの管理画面でサイドメニューでFunctionsを選ぶとデプロイされたFunctionが確認できます。
表示されているURLの末尾に?serialCode=xxxx-yyyy-zzzz
をつけてブラウザからアクセスした場合に、Jsonが返って来ることが確認できればFunctionの作成は完了です。
urlの例:
https://[プロジェクトID].cloudfunctions.net/customAuth?serialCode=xxxx-yyyy-zzzz
レスポンスの例:
{"customToken": "****~700文字前後~****"}
Unityからの認証
Firebase側の準備ができたのでUnity側でカスタム認証を行う処理を実装していきます。
サンプルコード:
// APIキーはFirebaseのサイドメニューの「プロジェクトの概要」右側の歯車の「プロジェクトを設定」を開くと「ウェブ API キー」の部分に表示されています
private string _apiKey = "APIキーを設定してください";
public void CustomTokenSignin()
{
var inputSerialCode = GameObject.Find("InputSerialCode").GetComponent<InputField>().text;
var resultText = GameObject.Find("ResultText").GetComponent<Text>();
var customToken = GetCustomToken(inputSerialCode);
var signInResult = SignInWithCustomToken(customToken);
Debug.Log($"idToken: {signInResult.idToken}");
Debug.Log($"refreshToken: {signInResult.refreshToken}");
resultText.text = "サインインに成功しました";
}
[Serializable]
class GetCustomTokenResponse
{
public string customToken;
}
string GetCustomToken(string serialCode)
{
WebClient wc = new WebClient();
wc.Headers[HttpRequestHeader.ContentType] = "application/json";
// urlには「Functionのデプロイの確認」で動作確認したURLを設定します
var url =
$"https://[プロジェクトID].cloudfunctions.net/customAuth?serialCode={serialCode}";
var response = wc.DownloadString(new Uri(url));
var customTokenResponse = JsonUtility.FromJson<GetCustomTokenResponse>(response);
return customTokenResponse.customToken;
}
FirebaseApi.SignInWithCustomTokenResponse SignInWithCustomToken(string token)
{
WebClient wc = new WebClient();
wc.Headers[HttpRequestHeader.ContentType] = "application/json";
var url = $"https://identitytoolkit.googleapis.com/v1/accounts:signInWithCustomToken?key={_apiKey}";
var requestBody = new FirebaseApi.SignInWithCustomTokenRequest(token);
var json = JsonUtility.ToJson(requestBody);
var response = wc.UploadString(new Uri(url), json);
return JsonUtility.FromJson<FirebaseApi.SignInWithCustomTokenResponse>(response);
}
GetCustomToken関数は前述の手順で作成したFunctionを使ってFirebase Authenticationへのサインイン用のカスタムトークンを取得する処理です。
SignInWithCustomToken関数はFunctionから返ってきたカスタムトークンを使ってサインインする処理です。サインインに成功するとFirebaseの様々なサービス横断で認証に使用できるidToken
とrefreshToken
を取得できます。
参考
Discussion