日記
Nuxt.js + Firebaseで、お酒の写真とコメントを管理するWebアプリをつくってる。
使用ユーザーは奥さんの1名だけ。
とりあえずなにかしらWebアプリを完成させたい、という目標を達成するために必要最低限の機能は一通り実装できた。
使用ユーザーは奥さん1名だけなので、ログイン機能なんかいらないんだけれども、FirebaseのRealtimeDatabseのルールが誰でも書き込める、だとさすがにどうなのかなという思いから認証機能を実装することにした。
※認証機能よりも画像の表示をなんとかしたほうがいいのはわかってるんだ。
本題
ユーザーの管理をFirebaseで行う
FIrebaseでの認証は以前、Udemyの以下のNuxt.jsの講習でさわったことがあったので、以下の講習内容と
https://www.udemy.com/nuxtjs-vuejs-on-steroids/
Firebase公式の内容で復習を行うことにしました。
Firebase でユーザーを管理する | Firebase
Eメールとパスワードでユーザー管理する
Firebaseの認証方法はいろいろあって、一番初歩的なログイン画面をつくって、Eメール、パスワードを入力させて認証するものから、Google認証のようにOAuth2をベースにした認証やらなんやらがいっぱいある。
このWebアプリのために、ユーザーとパスワードを管理してもらうのは申し訳ないので、最終的にはGoogle認証等に移行するつもりですが、とりあえずは初歩的なEメールとパスワード認証を使ってみることにします。
Firebaseの認証について
FirebaseのAuthenticationという機能で特段サーバ等を用意せずともユーザーの管理ができてしまう恐ろしい子。
Firebaseのコンソールで「Authencication」⇒「ユーザー」を参照すると、後述する処理で登録したユーザーの一覧を参照することができる。
こちらのFirebaseのAuthenticationの機能と、データを管理するFirebaseのRealtimeDatabaseを組み合わせて、ログイン機能を実装していく。
まずはログイン画面を作成する
とりあえずは、こんな感じのログイン画面を作成します、
画面は、login.vue
というVueコンポーネントで実装しました。
login.vue
<template lang="pug">
.login
label.label email
input.input(type="text" v-model="email")
label.label password
input.input(type="text" v-model="password")
button.button(@click="login") login
</template>
<script>
export default {
data() {
return {
email: '',
password: '',
}
},
methods: {
async login() {
}
}
firebase.authを使わない方法
認証を行うにあたっては、firebase.authという便利なパッケージがあるのでこちらを使うのが基本だ思う。
だけど、前述のUdemyの講習ではfirebase.authを使っていなかったので、復習の意味を込めて一旦firebase.authを使わないでやってみます。
といっても、firebase.authの内部でやっていることを、直接やるだけの話です。
さきほどのlogin.vue
について、ログインボタンを押した場合の処理を追記します。
login.vueを抜粋
<script>
export default {
data() {
return {
email: '',
password: '',
}
},
methods: {
async login() {
const url = 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=' + process.env.fbAPIKey
try {
const token = await this.$axios.$post(url ,{
email: this.email,
password: this.password,
returnSecureToken: true
})
localStorage.setItem('token', token.idToken)
localStorage.setItem('tokenExpiration', token.expiresIn)
} catch(error) {
console.log(error)
}
}
}
}
</script>
Firebaseのユーザーの作成 or ユーザーの認証のエンドポイントに対して、EメールとパスワードとfirebaseのAPIKeyをつけてなげるだけです。
上記APIは以下のドキュメントを参考にしています。
https://firebase.google.com/docs/reference/rest/auth
APIのキーは、Firebaseのコンソール画面にある↓のような箇所に書いてあるやつですね。
さて、上記login.vue
に記載されている処理を実行すると、以下のようなレスポンスが返ってきました。
ユーザーの新規作成APIの結果
{
"error": {
"code": 400,
"message": "OPERATION_NOT_ALLOWED",
"errors": [
{
"message": "OPERATION_NOT_ALLOWED",
"domain": "global",
"reason": "invalid"
}
]
}
}
どうやらFirebaseのAuthenticationの設定でログイン方法の設定を行っておく必要があるみたいです。
上記設定を行った後に、再度適当なメールアドレス、パスワードを設定したところ、無事リクエストが通りました。
ユーザーの新規作成APIの結果
{
"kind": "identitytoolkit#SignupNewUserResponse",
"idToken": "省略",
"email": "tekitouna@email.com",
"refreshToken": "省略",
"expiresIn": "3600",
"localId": "b7NUgSEZIZavcPVADGR27Fg0XgZ2"
}
リクエストの結果、idToken
なるものが返ってきたので、これをlocalstorageに保存しておくことにします。
このtokenをRealTimeDataBaseを参照するREST APIに渡して、tokenをもとに認証されたユーザーのみデータベースの内容を書き込むことができる、という設定に変更することで今回やりたいことが実現できそうです。
firebase.authを使う方法
さきほどは、https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword
等のAPIを直接叩いていましたが、通常はfirebase.authの機能を使えばよさそうです。
なので、さっそくfirebase
のパッケージをインストールします。
firebaseをインストール
$ npm install --save firebase
今回はNuxt.jsを使用しているので、plugin
としてFirebaseの初期設定処理を行っています。
初期設定の値は、ウェブアプリに Firebase を追加で取得できる値を設定します。
また、firebase
にはいろんなパッケージが含まれているので、必要最低限のものだけimportするようにします。
ここではfirebaseのコアであるfirebase/app
と認証のパッケージであるfirebase/auth
をimportします。
firebase.js
import firebase from 'firebase/app'
import 'firebase/auth'
import 'firebase/database'
if (!firebase.apps.length) {
firebase.initializeApp({
apiKey: process.env.fbAPIKey,
})
}
export default firebase
あとは、さきほど同様にlogin.vue
でfirebase.authの認証用のメソッドを呼ぶだけになります。
login.vueを抜粋
<script>
import firebase from '~/plugins/firebase'
export default {
data() {
return {
email: '',
password: '',
}
},
methods: {
async login() {
try {
const user = await firebase.auth().signInWithEmailAndPassword(this.email, this.password)
const token = await firebase.auth().currentUser.getIdToken(true)
localStorage.setItem('token', token.idToken)
} catch(error) {
console.log(error)
}
}
}
}
</script>
一点、firebase.authを使わなかった場合、tokenの値は直接取得できていましたが、firebase.authではtokenを取得するためにfirebase.auth().currentUser.getIdToken()
を使う必要があるみたいです。
こちらですが、tokenの有効期限が切れた後に、もっかい呼ぶと、リフレッシュトークンをもとに、新しいtokenを返却してくれるという素晴らしいものになっているみたいです。
当初はtokenの有効期限もクライアント側に保持して、意識する必要があるのかななんて思ってたんですが、getIdTokenを使えば、有効期限を気にしなくてもよくなるのかしら。
tokenを使ってRealtimeDatabaseのREST APIの認証を行う
さきほど取得したtokenを使って、RealtimeDatabaseの認証の設定を行ってみます。
RealtimeDatabaseはデータを取ってくるだけであれば、KEY名に.json
をつけてあげるだけで簡単に取得できますね。
私の場合、articles
とうキーにオブジェクトをぶらさげているので、以下のような形になります。
REST APIでデータを取得する
https://自分のrealtimedatabaseのdomain/articles.json
現状、上記にアクセスすると誰でもarticles.json
の内容を参照することができます。
これをログインしたユーザーのみ参照できる、という設定に変えてみます。
Firebaseのコンソール画面より、「Database」⇒「RealtimeDatabase」⇒「ルール」を開き、以下のようにread
の設定にauth!=null
を設定しています。
auth
は、認証されたユーザーの情報が設定されるみたいです。
実際に試してみると、さきほどまでアクセスできていたhttps://自分のrealtimedatabaseのdomain/articles.json
を参照すると、Permission Denied
と言われます。
しかしhttps://自分のrealtimedatabaseのdomain/articles.json?auth=取得したidToken
をつけてアクセスすることで、REST APIが認証され、articles.json
の内容を取得することができました。
ものすごく簡単にできちゃいますね。
この調子でGoogle認証もやってみたいと思います。