Форма авторизации на Vue для Symfony

Для того чтобы эффективно использовать разделение проекта на клиентскую и серверную части
я рекомендую установить LexikJWTAuthenticationBundle,
который позволяет использовать JWT(Json Web Token) аутентификацию для ваших API на Symfony.

Подробности установки и настройки подробно написаны в документации к бандлу, поэтому останавливаться на них я не вижу смысла.

Для демонстрации примера был создан репозиторий https://github.com/symfonyst/office

Для верстки я буду использовать CSS-библиотеку TailwindCSS, так как она существенно ускоряет скорость разработки проектов.

Также будут использоваться Vuex и VueRouter

Обработка формы

Она реализована в компоненте /src/views/Login.vue
Рассмотрим некоторые тонкости. Нам необходимо создать метод submit(), который отправит логин и пароль пользователя.

Запрос осуществляется через Vuex c последующей обработкой Promise

            
        import {CHECK_AUTH} from "../store/actions.types";
        import {mapGetters} from 'vuex'
        export default {
            name: "Login",
            data(){
              return {
                username: null,
                password: null,
              }
            },
            computed:{
              ...mapGetters(['authStatus']),
            },
            methods:{
              submit(){
                const {username, password, authStatus} = this
                const $this = this
                this.$store.dispatch(CHECK_AUTH, {username, password}).then(()=>{
                  if(authStatus === 'success'){
                    $this.$router.push('/')
                  }
                })
              }
            }
        }
            
        

VueRouter

Теперь перейдем к нашим роутам.
Для проверки авторизации пользователя перед переходом в раздел нужно указать для свойства роута beforeEnter функцию ifAuthenticated

Она запрашивает геттер с токеном авторизации, если он отсутствует, то перенаправляет на страницу авторизации.

            
            import Vue from 'vue'
            import VueRouter from 'vue-router'
            import Profile from '../views/Profile.vue'
            import Store from '../store'

            const ifNotAuthenticated = (to, from, next) => {
              if (!Store.getters.isAuthenticated) {
                next()
                return
              }
              next('/')
            }

            const ifAuthenticated = (to, from, next) => {
              if (Store.getters.isAuthenticated) {
                next()
                return
              }
              next('/login')
            }

            Vue.use(VueRouter)

            const routes = [
              {
                path: '/',
                name: 'Profile',
                component: Profile,
                beforeEnter: ifAuthenticated
              },
              {
                path: '/news',
                name: 'News',
                component: () => import('../views/News.vue'),
                beforeEnter: ifAuthenticated
              },
              {
                path: '/login',
                name: 'Login',
                component: () => import('../views/Login'),
                beforeEnter: ifNotAuthenticated
              }
            ]

            const router = new VueRouter({
              routes
            })

            export default router

            
        

Также у нас присутствует функция ifNotAuthenticated в роуте для /login. Она проверяет пройдена ли авторизацию и перенаправляет в главный раздел авторизованного пользователя.

Хранение токена авторизации

            
        export default new Vuex.Store({
          state: {
            token: localStorage.getItem('user-token') || '', // Будем хранить токен в localStorage
            status: typeof(localStorage.getItem('user-token')) != 'undefined' ? 'success':'',
            hasLoadedOnce: null,
          },
          mutations: {
            [AUTH_REQUEST]: (state) => {
              state.status = 'loading'
            },
            // Сохранение токена авторизации
            [AUTH_SUCCESS]: (state, value) => {
              state.status = 'success'
              state.token = value.data.token
              state.hasLoadedOnce = true
            },
            [AUTH_ERROR]: (state, err) => {
              state.status = err
              state.hasLoadedOnce = true
            },
            // Удаление токена авторизации
            [SET_AUTH_LOGOUT]: (state) => {
              state.token = ''
            }
          },
          getters: {
            isAuthenticated: state => !!state.token, // Геттер получения токена авторизации
            authStatus: state => state.status,
          },
                // ...