Как сделать базовую аутентификацию в Vue.js с помощью Google Firebase

Иногда, как разработчики, мы хотим создать простой прототип, чтобы сделать MVP (продукт с минимальной стоимостью) нашей идеи стартапа. Если вы знаете основы использования Javascript и Vue.js, вы можете подготовить свою базу mvp за считанные минуты.

В этом проекте мы хотим подготовить базовую аутентификацию и решить, куда может перейти зарегистрированный пользователь, а где - гость. В этом решении я собираюсь использовать Google Firebase - смешанные сервисные инструменты для быстрого создания приложений без управления инфраструктурой.

Прежде чем мы начнем

Прежде чем мы начнем, вам нужно перейти на console.firebase.google.com и создать новый проект. После этого на начальном экране вы можете установить флажок Добавить Firebase в свое веб-приложение, а затем вы сможете увидеть конфигурацию javascript. СКОПИРОВАТЬ!

Затем подумайте о настройке вашего модуля Auth. На боковой панели выберите РАЗРАБОТКА - ›Аутентификация. Перейдите на карту СПОСОБ ВОЙТИ и настройте 3 метода: электронная почта / пароль, Google и Facebook. Следуйте инструкциям во всплывающих окнах для настройки свойств. Если возникла проблема, дайте мне знать в комментарии - я собираюсь подготовить видео об этом.

Шаг 1. Инициализируйте новый проект Vue

Чтобы запустить наш проект, я собираюсь использовать Vue CLI с шаблоном webpack. Все, что думает о CLI, можно найти здесь.

$ vue init webpack auth-project

Во время установки CLI спросит вас о названии проекта, описании, авторе и т. Д. Если вы хотите подготовить модульный тест или линтер - просто измените ответ на «да». Важно: установите Vue build для автономной и install Vue router для Yes.

? Project name auth-project
? Project description A Vue.js project
? Author Michal Jurkowski
? Vue build standalone
? Install vue-router? Yes
? Use ESLint to lint your code? No
? Set up unit tests No
? Setup e2e tests with Nightwatch? No
? Should we run `npm install` for you after the project has been created? (recommended) npm
vue-cli · Generated “auth-project”.

Затем нам нужно войти в наш проект и установить дополнительные модули npm для использования Vuex (шаблон управления состоянием Vue), Firebase SDK и Firebase UI (встроенный компонент аутентификации firebase).

$ cd auth-project
$ npm install vuex firebase firebaseui --save

Шаг 2. Подготовьте простые представления

Следующим шагом будет создание в нашем каталоге src нового каталога с именем views. Здесь мы хотим создать 3 простых представления: Home, Auth, Dashboard. В нашем проекте вы начнете дома - это представление доступно для всех пользователей и гостей. Оттуда вы можете перейти к логину - Auth, где вы можете выбрать метод Auth. Вид панели инструментов предназначен для зарегистрированных пользователей - важное ограничение.

Из src/components снимаю HelloWorld.vue - не надо работать свойство в нашем проекте.

Мои 3 компонента в src/views выглядят так:

# src/views/Home.vue
<template>
  <div>
    <h1>Hello!</h1>
    <p>What you want to do?</p>
    <router-link to="/auth">Sign in</router-link>
  </div>
</template>

<script>
    export default {
        name: 'home'
    }
</script>

<style scoped>

</style>

Как видите, я использую <router-link> для подготовки привязки к нашей странице авторизации.

# src/views/Auth.vue
<template>
  <div>
    <h1>Sign in</h1>
  </div>
</template>

<script>
  export default {
    name: 'auth',
  }
</script>

<style scoped>

</style>

На шаге 5 мы собираемся реализовать здесь пользовательский интерфейс Firebase.

И последний наш файл - Dashboard:

# src/views/Dashboard.vue
<template>
  <div>
    <h1>Hello USER!</h1>
  </div>
</template>

<script>
    export default {
        name: 'dashboard'
    }
</script>

<style scoped>

</style>

Шаг 3. Создайте простую маршрутизацию

Теперь нам нужно создать простую маршрутизацию с ограничениями. Посмотрите на наши маршруты - для /auth и /dashboard я добавляю дополнительное свойство meta с двумя ключами: guestOnly (если это правда и пользователь зарегистрирован, мы перенаправим его на просмотр для пользователя - например, если пользователь хочет перейти на страницу входа, если он зарегистрирован) и requireAuth (если это правда и пользователь не вошел в систему, мы должны перенаправить его на страницу входа).

Для лучшей практики я использую History Mode из HTML5. Более подробную информацию вы можете найти здесь.

# src/router/index.js
import Vue from 'vue'
import Router from 'vue-router'

import Auth from '@/views/Auth'
import Dashboard from '@/views/Dashboard'
import Home from '@/views/Home'

Vue.use(Router)

var routes = [
  { path: '/home', name: 'home', component: Home },
  { path: '/auth', name: 'auth', component: Auth, meta: { guestOnly: true } },
  { path: '/dashboard', name: 'dashboard', component: Dashboard, meta: { requireAuth: true } },
  { path: '*', redirect: '/home' }
]

export const router = new Router({
  mode: 'history',
  routes
})

И теперь нам нужно подключить наш маршрутизатор к основному экземпляру Vue в main.js

import Vue from 'vue'

import App from '@/App'

import {router} from '@/router'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  template: '<App/>',
  components: { App }
})

Шаг 4: Подготовьте Vuex Store

Теперь у нас есть готовый простой SPA (одностраничное приложение). Но прежде чем мы начнем работать с firebase, мы должны подготовить наш Магазин для пользовательских данных. Лучшая практика во Vue - это работа с хранилищами управления состоянием. Все о Vuex вы можете прочитать здесь.

Первая хорошая практика - сделать независимый пользовательский модуль для управления пользовательскими состояниями. Для этого я создаю простую файловую структуру src/store с основным хранилищем (index.js) и пользовательским модулем (modules/user.js).

В этом примере я поместил эту структуру, потому что она может помочь вам понять пространства имен и способы масштабирования вашего приложения. Каждый модуль - это своего рода хранилище данных. Если вы разделите каждый модуль, все изменения в вашем приложении могут быть проще.

# src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'

import user from './modules/user'

Vue.use(Vuex)

export const store = new Vuex.Store({
    state: {

    },
    getters: {

    },
    mutations: {

    },
    actions: {

    },
    modules: {
        user
    }
})

Как вы можете видеть в этом файле, я готовлю основной Vuex Store и помещаю пользовательский модуль.

# src/store/modules/user.js
import Vue from 'vue'

const state = {
    user: null
}

const getters = {
    user: state => state.user,
    isLogged: state => (state.user !== null)
}

const mutations = {
    setUser: (state, user) => {
        state.user = user
    }
}

const actions = {

}

export default {
    namespaced: true,
    state,
    getters,
    mutations,
    actions
}

И теперь мы можем запустить наш магазин в main.js

# main.js
import Vue from 'vue'

import App from '@/App'

import {router} from '@/router'
import {store} from '@/store'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  store,
  router,
  template: '<App/>',
  components: { App }
})

Шаг 5. Создайте класс аутентификации

Если вы настроите свой проект firebase (инструкция находится в начале этого поста), тогда мы можем начать создавать класс аутентификации. Мы собираемся сделать единый файл, в котором будут представлены все методы авторизации.

# src/auth.js
import firebase from 'firebase'
import firebaseui from 'firebaseui';

const config = {
  apiKey: '#######',
  authDomain: '#######',
  databaseURL: '#######',
  projectId: '#######',
  storageBucket: '#######',
  messagingSenderId: '#######'
};

const auth = {
  context: null,
  uiConfig: null,
  ui: null,

  init(context) {
    this.context = context;

    firebase.initializeApp(config);
    this.uiConfig = {
      signInSuccessUrl: 'dashboard',
      signInOptions: [
        firebase.auth.FacebookAuthProvider.PROVIDER_ID,
        firebase.auth.GoogleAuthProvider.PROVIDER_ID,
        firebase.auth.EmailAuthProvider.PROVIDER_ID
      ]
    }
    this.ui = new firebaseui.auth.AuthUI(firebase.auth());

    firebase.auth().onAuthStateChanged((user) => {
      this.context.$store.dispatch('user/setCurrentUser')

      let requireAuth = this.context.$route.matched.some(record => record.meta.requireAuth)
      let guestOnly = this.context.$route.matched.some(record => record.meta.guestOnly)

      if(requireAuth && !user) this.context.$router.push('auth')
      else if (guestOnly && user) this.context.$router.push('dashboard')
    });
  },
  authForm(container) {
    this.ui.start(container, this.uiConfig);
  },
  user() {
    return this.context ? firebase.auth().currentUser : null;
  },
  logout() {
    firebase.auth().signOut();
  }
}

export default auth;

Не забудьте установить config с помощью ключей firebase.

Простое объяснение методов:

init(context) - мы хотим запустить его, когда приложение будет готово. Затем мы делаем доступ к основному экземпляру vue (предоставленному context) и инициализируем firebase и firebase ui с конфигурацией. Пользовательский интерфейс Firebase инициализируется тремя способами аутентификации - вход в Facebook, вход в Google и вход по электронной почте. И прикрепляем к объекту недвижимости на нашем сайте. Не забудьте установить signInSuccessUrl для перенаправления после входа в систему. Я прикрепляю дополнительный прослушиватель для состояния аутентификации пользователя - если он изменится, я хочу обновить информацию о пользователе в нашем магазине и посмотреть, где пользователь сейчас находится (маршрутизация) и может ли он там быть. Это ситуация, если пользователь вошел в систему и набрал в адресной строке /auth, чтобы принудительно открыть это представление. Это правило перенаправляет его на /dashboard, потому что он зарегистрирован.

authForm() - этот метод выполняет сборку пользовательского интерфейса Firebase в контейнере

user() - вернет текущий пользовательский объект, если он существует

logout() - это метод Firebase для выхода пользователя из системы

Но берегись! В init мы используем this.context.$store.dispatch('user/setCurrentUser'), но в магазине его нет! Итак, мы модифицируем src/store/modules/user.js

# src/store/modules/user.js
import Vue from 'vue'
import auth from '@/auth';

const state = {
    user: null
}

const getters = {
    user: state => state.user,
    isLogged: state => (state.user !== null)
}

const mutations = {
    setUser: (state, user) => {
        state.user = user
    }
}

const actions = {
    setCurrentUser: ({ commit }) => {
      commit('setUser', auth.user())
    }
}

export default {
    namespaced: true,
    state,
    getters,
    mutations,
    actions
}

Следующее, что нужно сделать, это обновить маршрутизатор, чтобы определить разрешения для гостей и пользователей.

# src/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import auth from '@/auth'

import Auth from '@/views/Auth'
import Dashboard from '@/views/Dashboard'
import Home from '@/views/Home'

Vue.use(Router)

var routes = [
  { path: '/home', name: 'home', component: Home },
  { path: '/auth', name: 'auth', component: Auth, meta: { guestOnly: true } },
  { path: '/dashboard', name: 'dashboard', component: Dashboard, meta: { requireAuth: true } },
  { path: '*', redirect: '/home' }
]

export const router = new Router({
  mode: 'history',
  routes
})

router.beforeEach((to, from, next) => {
  let currentUser = auth.user()
  let requireAuth = to.matched.some(record => record.meta.requireAuth)
  let guestOnly = to.matched.some(record => record.meta.guestOnly)

  if (requireAuth && !currentUser) next('auth')
  else if (guestOnly && currentUser) next('dashboard')
  else next()
})

Я прикрепляю в конце файла router.beforeEach, чтобы проверить наши правила и перенаправить, если это необходимо.

И последнее место - это main.js, где мы должны запустить наш модуль аутентификации.

# src/main.js
import Vue from 'vue'

import App from '@/App'

import {router} from '@/router'
import {store} from '@/store'
import auth from '@/auth'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  store,
  router,
  beforeCreate () {
    auth.init(this)
  },
  template: '<App/>',
  components: { App }
})

Шаг 6. Сделайте вид Auth

Чтобы сделать представление Auth, мы должны подготовить для них контейнер и после монтирования выполнить authForm из класса auth. Кроме того, мы можем импортировать firebase ui css.

# src/views/Auth.vue
<template>
  <div>
    <h1>Sign in</h1>
    <div id="firebaseui-auth-container"></div>
  </div>
</template>

<script>
  import auth from '@/auth'

  export default {
    name: 'auth',
    mounted() {
      auth.authForm('#firebaseui-auth-container')
    }
  }
</script>

<style>
  @import "../../node_modules/firebaseui/dist/firebaseui.css";
</style>

После этого наше Auth View выглядит так:

Шаг 7. Отобразите сведения о пользователе в Личном кабинете

Последнее, что нужно подумать, - это подготовить представление Dashboard и поместить туда данные пользователя.

# src/views/Dashboard.vue
<template>
  <div v-if="user">
    <h1>Hello USER!</h1>
    <img :src="user.photoURL" width="100"> <br>
    <h3>{{user.displayName}}</h3>
    <p>{{user.email}}</p>
    <button @click="logOut">Log out</button>
    <br><br><br>
    <pre>{{user}}</pre>
  </div>
</template>

<script>
  import auth from '@/auth'

  export default {
    name: 'auth-success',
    computed: {
      user() {
        return this.$store.getters['user/user']
      }
    },
    methods: {
      logOut() {
        auth.logout()
      }
    }
  }
</script>

<style scoped>
  img {
    border-radius: 50px;
  }

  h3 {
    margin-bottom: 0;
  }

  p {
    margin-top: 0;
  }

  pre {
    text-align: left;
  }
</style>

В итоге это выглядит так:

РЕЗЮМЕ

Как видите, этот прототип во Vue очень прост. Если вы используете какие-то внешние инструменты, такие как Firebase, вы можете сделать свои приложения очень быстрыми для простого распространения. Все исходники вы можете найти в публичном репозитории на Github.

Не стесняйтесь комментировать мое решение!