Firebase認証とデータベースを使用してVueSurveyアプリを構築する方法
公開: 2022-03-10
クイックサマリー↬このチュートリアルでは、Vue.jsとFirebaseを使用して機能調査アプリを構築するためのステップバイステップガイドを紹介します。 Vuelidateを介したユーザーのデータの検証から、認証、ユーザーのデータの保存、ルート保護、Firebaseサーバーへのデータの送信まで。 チュートリアルで使用されるすべての手順は実用的であり、カスタムバックエンドを使用する場合でも、実際のプロジェクトで再現できます。
このチュートリアルでは、調査アプリを作成します。このアプリでは、ユーザーフォームデータの検証、Vueでの認証の実装、VueとFirebase(BaaSプラットフォーム)を使用した調査データの受信について学習します。
このアプリを作成する際、ユーザーが登録時にフォームを送信する前であっても、バックエンドに連絡してメールがすでに受信されているかどうかを確認するなど、さまざまな種類のデータのフォーム検証を処理する方法を学習します。
また、アプリはRESTfulAPIを使用してユーザーのログインを処理します。 VueルーターのAuthguardを利用して、ログインしていないユーザーが調査フォームにアクセスできないようにし、ログインしたユーザーの調査データを安全なデータベースに正常に送信します。
同じページにいるので、Firebaseとは何か、このチュートリアルでFirebaseが何をするのかを明確にしましょう。 Firebaseは、「アプリを構築、改善、成長させる」ためのツールセットであり、開発者が通常は自分で構築する必要があるサービスの大部分にアクセスできますが、実際には構築したくないので、アプリのエクスペリエンス自体に焦点を当てます。 これには、分析、認証、データベース、ファイルストレージなどが含まれ、リストは続きます。
これは、通常、フロントエンドソフトウェアとバックエンドソフトウェアの両方を作成する従来のアプリ開発とは異なります。 フロントエンドコードは、バックエンドによって公開されているAPIエンドポイントを呼び出すだけで、バックエンドコードが実際に機能します。 ただし、Firebase製品では、従来のバックエンドがバイパスされ、作業がクライアントに渡されます。 これにより、技術的には、私のようなフロントエンドエンジニアがフロントエンドコードだけを記述してフルスタックアプリケーションを構築できるようになります。
ジャンプした後もっと! 以下を読み続けてください↓ つまり、Firebaseは、認証とデータベースの両方のニーズを処理するために必要なAPIエンドポイントを提供することで、このプロジェクトのバックエンドとして機能します。 最終的には、Vue + Firebaseを使用して機能調査アプリを作成します。 その後、カスタムバックエンドを使用する場合でも、これらの同じプロセスを使用して、任意のWebアプリを構築できます。
フォローするには、マシンにNodeとnpm / yarnがインストールされている必要があります。 まだ行っていない場合は、これらのクイックガイドに従って、yarnまたはnpmをマシンにインストールしてください。 このチュートリアルでは、Vue、Vuex、およびVueルーターの構文についての基本的な知識も必要です。
このチュートリアルのスターターファイルはここにあり、このプロジェクトのベースファイルが含まれています。また、完成したデモのリポジトリもここにあります。 リポジトリのクローンを作成またはダウンロードして、ターミナルでnpm install
を実行できます。
スターターファイルをインストールすると、ウェルカムページが表示されます。このページには、サインアップしてサインインするためのオプションがあります。ログインすると、アンケートにアクセスできるようになります。
このプロジェクトを完全に自分で構築したい場合は、新しいプロジェクトを自由に作成してください。Vuex、Vueルーター、Vuelidate、およびaxiosをVueプロジェクトにインストールしてください。 では、すぐに始めましょう。
まず、このプロジェクトを設定するにはFirebaseアカウントが必要です。これは、アプリのコンテナを作成し、データベースへのアクセス、さまざまな認証手段、ホスティングなどを提供するのと非常によく似ています。一度設定するのは簡単です。 'Firebaseサイトにいます。
プロジェクトが完了したので、次は、Firebaseに認証システムとデータベース(リアルタイムデータベース)の両方をセットアップします。
- 「認証」オプションをクリックします。
- 必要な「サインイン方法」(この場合は電子メール/パスワード)を設定します。
- 「データベース」をクリックします。
- 「リアルタイムデータベース」を選択し、右上にあるこのリンクをコピーします。
Firebaseデータベースにデータを送信する場合は、APIエンドポイントとして非常に役立ちます。
このAPIをデータベースAPIと呼びます。 これを使用するには、送信時に選択したデータベースの名前を追加する必要があります。 たとえば、userというデータベースに送信します。 最後にuser.jsonを追加するだけです。
{databaseAPI}/user.json
この後、Firebase auth rest APIドキュメントに移動して、サインアップしてAPIエンドポイントにサインインします。 これらのエンドポイント内で、プロジェクトの設定にあるプロジェクトのAPIキーが必要になります。
検証
コードに戻ると、ユーザーが適切な情報を送信していることを確認するために、サーバーに送信される前にサインアップデータの検証が行われます。 Vueでの検証を容易にするクールなライブラリであるVuelidateを使用します。 まず、Vuelidateをプロジェクトにインストールします。
npm i vuelidate
src/components/auth/signup.vue
に移動し、スクリプトタグ内でvuelidateと、以下に示すようにライブラリから必要なすべての必要なイベントをインポートします。
注:ライブラリと利用可能なすべてのイベントの完全な概要については、ドキュメントを確認してください。
import { required, email, numeric, minValue, minLength, sameAs } from 'vuelidate/lib/validators'
簡単な説明:
価値 | 説明
---|
required | 値は必須です |
email | 値はメールである必要があります |
numeric | 数字でなければなりません |
minValue | ユーザーが入力できる最小の数値。 |
sameAs | 2つの値を比較して、それらが同じであることを確認するために使用されます |
また、[`axios`](https://github.com/axios/axios)をインポートして、サーバーにHTTPリクエストを送信できるようにします。
import axios from 'axios'
先に進む前に、以下に示すように、必要に応じて電子メールを検証できるように、データベースにいくつかのルールを追加する必要があります。
"read" = "true"
これは、データベースをクライアント側から支障なく読み取ることができることを意味します。
"write" = "auth" !== null
認証されたユーザーでない限り、データベースに書き込むことはできません。
"Users" = { "onIndex" : ["email"] }
これにより、「email」のインデックスを使用して「users」ドキュメントをクエリできます。 つまり、データベースを文字通りフィルタリングして、一意の電子メールを探すことができます。 次に、メソッドや計算などと同じように、「validations」という名前のカスタム計算プロパティを追加します。「validations」の下に、必要な「email」から始まる必要なデータを検証するメソッドがあります。 。 また、ユーザーがすべてカスタムバリデーター内で非同期バリデーターと呼ばれるものを使用して入力した後にデータベースをチェックすることで、他の誰かがすでにメールを受信したことをユーザーに知らせたいと考えています。これはすべて[vuelidate。 ](https://vuelidate.js.org/#sub-asynchronous-validation)
validations : { email: { required, email, unique: val => { if (val === '') return true return axios.get('https://vue-journal.firebaseio.com/users.json?orderBy="email"&equalTo="' + val + '"') .then(res => { return Object.keys(res.data).length === 0 }) } } }
次に、uniqueの下で、axiosを使用してデータベースにクエリを実行し、デフォルトのObject.keysを使用して、長さが0の場合にのみ応答を返します。年齢については、 `minValに割り当てられたrequired、numeric、およびmin値18を追加します。そのプロパティとして `。
age: { required, numeric, minVal: minValue(18) }
パスワードのプロパティが必要であり、 `minLen`に割り当てられる最小の長さは6です。
password: { required, minLen: minLength(6) }
`confirmPassword`プロパティは、基本的にパスワードと同じである必要があります。
confirmPassword: { sameAs: sameAs(vm => { return vm.password }) }
メールが受信されたことをユーザーに通知するには、 `v-if`を使用して` unique`がtrueかfalseかを確認します。 trueの場合、返されるオブジェクトの長さが0であり、電子メールを引き続き使用でき、その逆も可能であることを意味します。 同様に、 `v-if`を使用して、ユーザー入力が実際の電子メールであるかどうかを確認できます。 そして、個々の入力の周囲のすべてのdivに対して、その入力でエラーが発生するとアクティブになる無効なクラスを追加します。 検証イベントをHTMLの各入力にバインドするには、 `メールで見られるように[` $ touch() `](https://vuelidate.js.org/#sub-without-v-model)を使用します。 `以下。
<div class="input" :class="{invalid: $v.email.$error}"> <h6 v-if="!$v.email.email">Please provide a valid email address.</h6> <h6 v-if="!$v.email.unique">This email address has been taken.</h6> <input type="email" placeholder="Email" @blur="$v.email.$touch()" v-model="email"> </div>
`Age`、` password`、および `confirmPassword`は、` email`と同様の方法でHTML入力にバインドされます。 また、入力のいずれかにエラーがある場合は、[送信]ボタンを非アクティブにします。
<button type="submit" :disabled="$v.$invalid">create</button>
これは、このvuelidateセクションの完全な[CodePenの例](https://codepen.io/atanda1/pen/Yzyqrjv)です。
##認証このアプリはSPAであり、従来のサイトのようにリロードされないため、アプリ内のすべてのコンポーネントが一般的な認証ステータスを認識できるようにするための単一の「信頼できる情報源」としてVuexを使用します。 ストアファイルに移動し、アクション内でサインイン/サインアップメソッドの両方を作成します。 ユーザーデータを送信するときに受信した応答( `token`と` userId`)は、州内に保存されます。 トークンは、アプリ内のどの時点でもまだログインしているかどうかを知るために使用されるため、これは重要です。 `token`、` userId`、およびuserは、初期値がnullの状態で作成されます。 後でユーザーに連絡しますが、ここでは最初の2つに焦点を当てます。
state: { idToken: null, userId: null, user: null }
次に、必要に応じて状態を変更するためのミューテーションが作成されます。
authUser | トークンとuserId を保存します |
storeUser | ユーザー情報を保存します |
clearAuthData | データを消去して初期状態に戻します |
mutations: { authUser (state, userData) { state.idToken = userData.token state.userId = userData.userId }, storeUser (state, user) { state.user = user }, clearAuthData (state) { state.idToken = null state.userId = null state.user = null } }
サインアップ/サインインの場合、両方に対して個別のアクションを作成する必要があります。ここで、認証要求をサーバーに送信します。 その後、サインアップ/サインインからの応答(トークンとuserId)がauthUserにコミットされ、ローカルストレージに保存されます。
signup ({commit, dispatch}, authData) { axios.post('https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=AIzaSyCFr-OMMzDGp4Mmr0t66w2cTGfNazYjptQ', { email: authData.email, password: authData.password, returnSecureToken: true }) .then(res => { console.log(res) commit('authUser', { token: res.data.idToken, userId: res.data.localId }) localStorage.setItem('token', res.data.idToken) localStorage.setItem('userId', res.data.localId) localStorage.setItem('email', res.data.email) dispatch('storeUser', authData) setTimeout(function () { router.push('/dashboard') }, 3000) }) .catch(error => console.log(error)) }
login ({commit}, authData) { axios.post('https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=AIzaSyCFr-OMMzDGp4Mmr0t66w2cTGfNazYjptQ', { email: authData.email, password: authData.password, returnSecureToken: true }) .then(res => { console.log(res) localStorage.setItem('token', res.data.idToken) localStorage.setItem('userId', res.data.localId) localStorage.setItem('email', res.data.email) commit('authUser', { token: res.data.idToken, userId: res.data.localId }) router.push('/dashboard') }) .catch(error => console.log(error.message)) }
ただし、ここで注意が必要なのは、サインアップアクションで行うことです。特に、認証データベースに登録する電子メールとパスワードのみを送信することです。 本当の意味で、私たちはこの認証データベースのデータを使用するためのアクセス権を持っておらず、電子メール/パスワード以外のサインアップデータも送信していません。 したがって、別のアクションを作成して、完全なサインアップデータを別のデータベースに送信します。 この別のデータベースドキュメントでは、そこに保存することを選択したすべての情報に完全にアクセスできます。 この新しいアクションを `storeUser`と呼びます。次に、サインアップアクションに移動し、サインアップデータを含むオブジェクト全体を` storeUser`を介してアクセスできるデータベースにディスパッチします。 **注:**セキュリティ上の理由から、 `storeUser`を含むユーザーのパスワードをデータベースに送信したくない場合があります。
storeUser ({ state}, userData) { if (!state.idToken) { return } axios.post('https://vue-journal.firebaseio.com/users.json' + '?auth=' + state.idToken, userData) .then(res => console.log(res)) .catch(error => console.log(error)) } }
`storeUser`は、データベースへの投稿中に、新しく取得したトークンとデータベースAPIを使用してクエリを追加します。 これは、証明(トークン)で認証されている場合を除いて、データベースに書き込むことができないためです。 それが最初にFirebaseに与えたルールです覚えていますか?
“write” = “auth” !== null
サインアップ/サインインアクションの完全なコードは[ここ](https://codepen.io/atanda1/pen/mdePKqj)にあります。 次に、サインアップとサインインの両方を、 `onSubmit`メソッド内のコンポーネントからストア内のそれぞれのアクションにディスパッチします。
methods : { onSubmit () { const signupData = { email : this.email, name : this.name, age : this.age, password : this.password, confirmPassword : this.co nfirmPassword } this.$store.dispatch('signup', signupData) } } }
**注:** `signupData`にはフォームのデータが含まれています。
methods : { onSubmit = { const formData = { email : this.email, password : this.password } this.$store.dispatch('login', {email: formData.email, password: formData.password}) } }
## AuthGuard AuthGuardは、ログインしていないユーザーがアンケートを送信するダッシュボードにアクセスできないようにする必要があります。 ルートファイルに移動し、ストアをインポートします。
import store from './store'
ルート内で、ダッシュボードのパスに移動し、以下を追加します。
const routes = [ { path: '/', component: WelcomePage }, { path: '/signup', component: SignupPage }, { path: '/signin', component: SigninPage }, { path: '/dashboard', component: DashboardPage, beforeEnter (to, from, next) { if (store.state.idToken) { next() } else { next('/signin') } } } ]
これは、状態にトークンがあるかどうかを確認することだけです。ある場合は、ダッシュボードへのアクセスを許可します。その逆も同様です。 ## LogOutログアウトオプションを作成するには、以前に `mutations`で作成した` clearAuth`を使用します。これは、 `token`と` userId`の両方を `null`に設定するだけです。 ここで、新しい `logout`` action`を作成します。これは、` clearAuth`にコミットし、ローカルストレージを削除し、 `router.replace( '/')`を追加して、ユーザーを完全にリダイレクトします。
actions: { logout ({commit}) { commit('clearAuth') localStorage.removeItem('token') localStorage.removeItem('userId') router.replace('/') } }
ヘッダーコンポーネントには、ストアでログアウトアクションをディスパッチする `onLogout`メソッドがあります。
methods: { onLogout() { this.$store.dispatch('logout') } }
次に、[ここ](https://codepen.io/atanda1/pen/jObqKNd)にあるように、 `onLogout`メソッドを起動するボタンに` @ click`を追加します。
<ul @click="onLogout">Log Out</ul>
## UI_Stateダッシュボードへの条件付きアクセスを許可したので、次のステップは、ダッシュボードをナビゲーションバーから削除して、認証されたユーザーのみがダッシュボードを表示できるようにすることです。 これを行うには、状態内のトークンがnullであるかどうかをチェックする、 `ifAuthenticated`と呼ばれる` getters`の下に新しいメソッドを追加します。 トークンがある場合は、ユーザーが認証されていることを示しており、ナビゲーションバーの調査ダッシュボードオプションを表示する必要があります。
getters: { isAuthenticated (state) { return state.idToken !== null } }
その後、ヘッダーコンポーネントに戻り、computedの下にメソッド `auth`を作成します。このメソッドは、ストアで作成した` getters`内の `isAuthenticated`にディスパッチします。 これは、トークンがない場合、 `isAuthenticated`がfalseを返すことを意味します。つまり、` auth`もnullになり、その逆も同様です。
computed: { auth () { return this.$store.getters.ifAuthenticated } }
この後、HTMLに `v-if`を追加して、` auth`がnullかどうかを確認し、そのオプションがナビゲーションバーに表示されるかどうかを判断します。
<li v-if='auth'> <router-link to="/dashboard">Dashboard</router-link> </li> <li v-if='!auth'> <router-link to="/signup">Register</router-link> </li> <li v-if='!auth'> <router-link to="/signin">Log In</router-link> </li>
-UI状態セクションの完全なコードは[ここ](https://codepen.io/atanda1/pen/QWjNxyo)にあります。
AutoLogin
アプリをリロードすると、データが失われてサインアウトし、最初からやり直す必要があります。 これは、トークンとIDがjavascriptであるVuexに保存されているためです。これは、更新時にアプリがブラウザーで再読み込みされることを意味します。
そして最後に、ローカルストレージ内のトークンを取得します。 そうすることで、ウィンドウを更新するタイミングに関係なく、ブラウザーにユーザーのトークンを表示し、トークンがまだ有効である限り、ユーザーに自動ログインするメソッドを設定できます。
AutoLogin
と呼ばれる新しいactions
メソッドが作成されます。このメソッドでは、ローカルストレージからトークンとuserId
を取得し、ミューテーションでauthUser
メソッドにデータをコミットします。
actions : { AutoLogin ({commit}) { const token = localStorage.getItem('token') if (!token) { return } const userId = localStorage.getItem('userId') const token = localStorage.getItem('token') commit('authUser', { idToken: token, userId: userId }) } }
次に、App.vueに移動し、 created
メソッドを記述します。このメソッドは、アプリが読み込まれるたびにストアからautoLogin
をディスパッチします。
created () { this.$store.dispatch('AutoLogin') }
Fetch_User_Data
ユーザーの名前を表示して、ダッシュボードにユーザーを歓迎します。 そのため、 fetchUser
という別のアクションが作成されます。このアクションは、通常どおりトークンがあるかどうかを最初にチェックします。 次に、ローカルストレージから電子メールを取得し、電子メールの検証で以前に行ったようにデータベースにクエリを実行します。
これにより、サインアップ時に最初に送信されたユーザーのデータを含むオブジェクトが返されます。 次に、このオブジェクトを配列に変換し、最初に作成されたstoreUser
ミューテーションにコミットします。
fetchUser ({ commit, state}) { if (!state.idToken) { return } const email = localStorage.getItem('email') axios.get('https://vue-journal.firebaseio.com/users.json?orderBy="email"&equalTo="' + email + '"') .then(res => { console.log(res) // const users = [] console.log(res.data) const data = res.data const users = [] for (let key in data) { const user = data[key] user.id = key users.push(user) console.log(users) } commit('storeUser', users[0]) }) .catch(error => console.log(error)) }
その後、 storeUser
を介してすでにコミットされているstate.user
を返すuser
という別のゲッターを作成します。
getters: { user (state) { return state.user }, isAuthenticated (state) { return state.idToken !== null } }
ダッシュボードに戻り、ユーザーが存在する場合にのみstate.user.name
を返すname
という新しい計算メソッドを作成します。
computed: { name () { return !this.$store.getters.user ? false : this.$store.getters.user.name } }, created () { this.$store.dispatch('fetchUser') } }
また、ページが読み込まれると、 created
された計算プロパティを追加して、 fetchUser
アクションをディスパッチします。 次に、名前が存在する場合に名前を表示するために、HTMLでv-if
を使用します。
<p v-if="name">Welcome, {{ name }} </p>
Send_Survey
調査を送信するために、データベースAPIを使用してデータベースにデータを送信するpostData
アクションを作成し、ユーザーがログインしていることをサーバーに示すトークンを使用します。
postData ({state}, surveyData) { if (!state.idToken) { return } axios.post('https://vue-journal.firebaseio.com/survey.json' + '?auth=' + state.idToken , surveyData) .then(res => { console.log(res) }) .catch(error => console.log(error)) }
ダッシュボードコンポーネントに戻り、ストアのpostData
アクションにデータをディスパッチします。
methods : { onSubmit () { const postData = { price: this.price, long: this.long, comment: this.comment } console.log(postData) this.$store.dispatch('postData', postData) } }
これで、Firebaseサーバーとの通信中にデモアプリケーションに多くの便利な機能が実装されました。 うまくいけば、これらの強力な機能は、今日の最新のWebアプリを構築するために非常に重要であるため、次のプロジェクトで使用することになります。
ご不明な点がございましたら、コメント欄にご記入ください。すべての質問にお答えさせていただきます。
役立つと思われるその他のリソースには、次のものがあります。
- Firebaseとそれが提供するその他のサービスの詳細については、ChrisEsplinの記事「Firebaseとは」をご覧ください。
- Vuelidateは、本当に掘り下げるべき本当に素晴らしいライブラリです。 完全な洞察を得るために、そのドキュメントを読む必要があります。https://vuelidate.js.org/。
- 特に大規模なプロジェクトで使用する場合は、axiosを単独で探索することもできます。