2022年2月追記
Firebase SDK v9では、実装方法が大きく変わりました。
v9を利用した認証の実装については、以下をご覧ください。
Authenticationを利用した実装
前回 に続き、 Firebase の備忘録を書いていきます。
今回はFirebase Authenticationを利用した認証システムの実装についてメモを残しておきます。
Firebase Authentication の設定
認証は、Firebase プロジェクトのコンソールから「Auhentication」を選んで設定していきます。
公式ドキュメントは以下。
ここでは、サンプルアプリで利用したGoogle 認証に絞って記述します。
Google 認証の設定
Authentication → Sign-in methodを選び、設定を「有効」に変更→保存で、終了。
Google認証の実装
Firebase SDKを利用します。
前項で書いた通り、認証用のSDKと構成オブジェクトのロードを済ませておきます。
<script src="/__/firebase/7.16.0/firebase-app.js"></script>
<script src="/__/firebase/7.16.0/firebase-auth.js"></script>
<script src="/__/firebase/init.js"></script>
実装方法は大まかに言うと
・Firebase UIの利用
・自前開発
の2つを選べます。
Firebase UIの利用
公式ドキュメントは こちら。
基本的な流れは
・Firebase UI用のJSファイルとCSSファイルをロード
・Firebase UIをウェブアプリ内で初期化
・ウェブアプリ内のDOMに表示
となります。
詳しい流れは公式ドキュメントの通りでOK。
https://firebase.google.com/docs/auth/web/firebaseui#before_you_begin
最初に、Firebase UI用のJSファイルとCSSファイルをロードします。ライブラリはhead要素内で読み込むように指定するようです。
<head>
<title>Firebase Authentication sample 01</title>
<script src="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.js"></script>
<link href="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.css" rel="stylesheet" type="text/css">
</head>
初期化
Googleを利用する場合の初期化は以下に記述されています。
サンプルコードではGoogle以外に、FacebookやTwitterなど、別な認証用の記述があります。今回のサンプルの様に、Googleによる認証のみ行う場合、他の手段は削除してOK。
サンプルコードでは「#firebaseui-auth-container」と言うIDのDOMを指定しているが、DOMの指定はなんでも良い。
ログインチェック
onAuthStateChangedメソッドを使います。
https://firebase.google.com/docs/auth/web/start#set_an_authentication_state_observer_and_get_user_data
サインアウト
サインアウトメソッドを実行するだけです。簡単。
firebase.auth().signOut().then(function() {
// Sign-out successful.
}).catch(function(error) {
// An error happened.
});
サンプルコード
これらを踏まえて、サンプルコードを実装してみました。仕様は以下の通り。
- Google を利用して認証する
- Firebase Authentication UIを利用して実装。
- 初期画面では、Googleのサインインボタンを表示
- サインインすると、Google ユーザーのユーザー名をウェルカムメッセージとともに表示する。
- サインアウト すると、Authentication UIの初期画面に戻る。
実際に動くサンプルは こちら で公開しています。
https://todomanage.web.app/sample/auth-sample01.html
サンプルコード
auth-sample01.html
<!DOCTYPE html>
<html lang="ja">
<head>
<title>Firebase Authentication sample 01</title>
<script src="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.js"></script>
<link href="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.css" rel="stylesheet" type="text/css">
</head>
<body>
<h1>Firebase Authenction Sample 01</h1>
<div id="auth"></div>
<script src="/__/firebase/7.16.0/firebase-app.js"></script>
<script src="/__/firebase/7.16.0/firebase-auth.js"></script>
<script src="/__/firebase/init.js"></script>
<script type="text/javascript">
/*
Firebase Authentcation を使った認証サンプル 01
Firebase Authentication UI を使い、サインイン用のUIを生成
ポップアップウィンドウで認証画面を表示、サインイン後元の画面に移動
サインアウト ボタンと、Googleの表示名をウェルカムメッセージとして表示
サインアウト 用の関数「signOut」を定義
*/
const ui = new firebaseui.auth.AuthUI(firebase.auth());
const uiConfig = {
callbacks: {
signInSuccessWithAuthResult: function(authResult, redirectUrl) {
return true;
},
},
signInFlow: 'popup',
signInSuccessUrl: 'auth-sample01.html',
signInOptions: [
firebase.auth.GoogleAuthProvider.PROVIDER_ID,
],
tosUrl: 'sample01.html',
privacyPolicyUrl: 'auth-sample01.html'
};
ui.start('#auth', uiConfig);
firebase.auth().onAuthStateChanged(user => {
if (user) {
const signOutMessage = `
<p>Hello, ${user.displayName}!<\/p>
<button type="submit" onClick="signOut()">サインアウト<\/button>
`;
document.getElementById('auth').innerHTML = signOutMessage;
console.log('ログインしています');
}
});
function signOut() {
firebase.auth().onAuthStateChanged(user => {
firebase
.auth()
.signOut()
.then(() => {
console.log('ログアウトしました');
location.reload();
})
.catch((error) => {
console.log(`ログアウト時にエラーが発生しました (${error})`);
});
});
}
</script>
</body>
</html>
独自UIで開発
基本はFirebase UIと変わらないです。
- Firebase Authentication を使ってAuthオブジェクトを作成
- 認証用のメソッドを呼び出し
となります。詳細は以下。
Google プロバイダ オブジェクトの作成
Firebase Authentication のSDKをロード後、プロバイダオブジェクトを生成します。
var provider = new firebase.auth.GoogleAuthProvider();
サインイン用のメソッドを呼び出す。
firebase.auth().signInWithPopup(provider).then(function(result) {
// 認証後の処理を記述します
}).catch(function(error) {
// エラー時の処理を記述します
});
認証用のメソッドはここにまとまっています。
認証後のユーザー情報
認証後のユーザー情報は「user」もしくは「userIInfo」メソッドで取得できます。
https://firebase.google.com/docs/reference/js/firebase.User
https://firebase.google.com/docs/reference/js/firebase.UserInfo
firebase.auth.user
firebase.auth.userinfo
サンプルコード
Authentication UI の時と同様、サンプルコードを書いてみました。仕様は以下の通りです。
- ボタンを押すと、ポップアップウィンドウが表示され、Google で認証できる
- 認証が成功したら、現在サインインしたユーザーの名前とメールアドレスがウェルカムメッセージとともに表示される
- サインアウト ボタンを押すと初期状態に戻る
動作サンプルは こちら。
サンプルコード
auth-sample02.html
<!DOCTYPE html>
<html lang="ja">
<head>
<title>Firebase Authentication sample 02</title>
<script src="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.js"></script>
<link href="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.css" rel="stylesheet" type="text/css">
</head>
<body>
<h1>Firebase Authenction Sample 02</h1>
<div id="auth"></div>
<script src="/__/firebase/7.16.0/firebase-app.js"></script>
<script src="/__/firebase/7.16.0/firebase-auth.js"></script>
<script src="/__/firebase/init.js"></script>
<script type="text/javascript">
/*
Firebase Authentcation を使った認証サンプル 02
Google認証用のオブジェクトを生成
認証用の関数「signIn」を定義
サインアウト 用の関数「signOut」を定義
認証の状態をチェックして、「サインイン」「サインアウト 」のボタンを出し分ける
*/
const provider = new firebase.auth.GoogleAuthProvider();
function signIn() {
firebase.auth().signInWithPopup(provider)
.then(result => {
console.log('ログインしました。');
}).catch(error => {
const signinError = `
サインインエラー
エラーメッセージ: ${error.message}
エラーコード: ${error.code}
`
console.log(signinError);
});
}
function signOut() {
firebase.auth().onAuthStateChanged(user => {
firebase
.auth()
.signOut()
.then(() => {
console.log('ログアウトしました');
location.reload();
})
.catch((error) => {
console.log(`ログアウト時にエラーが発生しました (${error})`);
});
});
}
firebase.auth().onAuthStateChanged(user => {
if (user) {
const signOutMessage = `
<p>Hello, ${user.displayName}!<\/p>
<button class="btn btn-primary" type="submit" onClick="signOut()">サインアウト<\/button>
`;
document.getElementById('auth').innerHTML = signOutMessage;
console.log('ログインしています');
} else {
const signInMessage = `
<button class="btn btn-primary" type="submit" onClick="signIn()">サインイン<\/button>
`;
document.getElementById('auth').innerHTML = signInMessage;
}
});
</script>
</body>
</html>
ユーザー情報取得のラグについて
Auhenticationで認証後、ウェブアプリでユーザー情報を取得しようとしてうまくいかない場合があります。
以下は、Firebaseのドキュメントに記述されている認証チェックのコードです。
var user = firebase.auth().currentUser;
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
認証が完了して、サインインが済んでいる状態でこのコードを使うと、認証中のユーザー情報「currentUser」の情報をもとに色々な処理が行えます。
一方で、サインイン直後にこのコードを使おうとすると、オブジェクト生成が完了する前に処理が走り、エラーが発生するケースが多い。
これを避けるためには「onAuthStateChanged」でユーザーの状態をチェックしてから処理するとうまくいきます。
認証が成功していれば、onAuthStateChanged メソッドからユーザーデータが含まれたオブジェクトが返るため、このデータを元にゴニョゴニョします。
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
}
});
自分はPromiseオブジェクトを生成して、ユーザーオブジェクトをresolveしてからゴニョゴニョしてみました。
// Firebase Authentication のPromiseオブジェクトを生成する関数を定義
function genUser() {
return new Promise((resolve, reject) => {
firebase.auth().onAuthStateChanged(user => {
if (user) {
resolve(user);
} else {
return null;
}
});
});
}
// Firebase の認証情報をResolveして処理ロジックに渡す
Promise.resolve(genUser()).then(user =>{
// user 内にGoogle認証を利用したユーザー情報が格納されている
console.log(user.uid);
console.log(user.displayName);
});