Форма авторизации на 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,
},
// ...