Приветствую разработчиков. Мы закончили основные аспекты нашей серверной архитектуры, теперь пора приступить к созданию внешнего интерфейса нашего приложения. Мы будем использовать Nuxt.js для создания наших форм входа и регистрации, чтобы позволить пользователям входить в систему и создавать учетные записи.
Оглавление
- Давайте создадим блог: введение в одностраничное приложение.
- Давайте создадим блог: модели, ассоциации, действия, политики и маршруты.
- Давайте создадим блог: электронные письма, индивидуальные ответы и Nuxt.js 2.0.
- Давайте создадим блог: войдите и зарегистрируйте интерфейс.
Первое, что нам нужно сделать, это убедиться, что в нашем API включен CORS. Для этого откройте backend/config/custom.js
и в свойстве cors
добавьте следующее:
allRoutes: true, // Apply CORS to every route in the api by default. allowOrigins: 'http://localhost:3000', // Allow requests from nuxt allowCredentials: true, // Allow cookie sharing within CORS requests
Следующее, что я сделал, - это создал inexistantUser
настраиваемый ответ, чтобы, если пользователь не найден, мы могли отловить ошибку и вывести ошибки в наши формы. Для этого создайте файл backend/api/reposnes/inexistantUser.js
и добавьте следующее:
module.exports = function inexistentUser(message) { const res = this.res; // Set result message let result = { status: 401, // Set custom message if it is passed into the response message: message ? message : 'The details provided does not match any user registered.' }; // Send JSON as that's what we want! return res.status(result.status).json(result); };
Теперь в рамках нашего действия проверки и входа в систему мы можем использовать настраиваемый ответ, чтобы выбросить inexistantUser
в качестве выхода:
exits: { ... other exits inexistentUser: { description: 'The details provided does not match any user registered.', responseType: 'inexistentUser', }, }, fn: async function (inputs, exits) { .... other code // if the user cannot be found throw a bad combo if(!user) throw 'inexistentUser'; ...... rest of code }
Теперь мы можем запустить sails lift
, чтобы запустить наш сервер, при включенном сервере нам нужно будет настроить хранилище приложений. Хранилище - это контейнер, в котором будет храниться состояние нашего приложения. Nuxt.js реализует Vuex в своем ядре, что позволяет нам добавлять наши модули satte в папку store
для чтения Nuxt и автоматической загрузки.
Во-первых, нам нужно установить базовый URL-адрес для Axios, чтобы открыть frontend/nuxt.config.js
и добавить baseURL: ‘http://localhost:1337'
к параметру axios
.
Чтобы иметь возможность использовать модули в нашем магазине, нам нужно добавить файл frontend/store/index.js
. Вместо создания экземпляра хранилища требуется экспортировать состояние как функцию, а мутации и действия как объекты.
// Store state export const state = () => ({}); // Store Actions export const actions = {}; // Store Mutations export const mutations = {};
Затем мы создадим для этого модуль учетной записи, создадим файл frontend/store/account.js
и добавим следующее:
// Account state export const state = () => ({ user: null, }); // Account actions export const actions = { USER_LOGIN({commit}, data) { // Send request to log in the user return this.$axios.put('api/v1/user/login', data) .then(res => { // Mutate the user state with logged in user commit('SET_USER', res.data); return res; }); }, USER_REGISTER({commit}, data) { // Send a request to register the user return this.$axios.post('api/v1/user/create', data) .then(res => { // Mutate the user state with newly registered user commit('SET_USER', res.data); return res; }); } }; // Account mutations export const mutations = { SET_USER(state, user) { // Mutate the user state state.user = user.id ? user : null; } };
Теперь, когда мы настроили наш магазин, мы можем создать нашу страницу входа в систему. С помощью Nuxt. js, мы можем автоматически сгенерировать конфигурацию vue-router из файлового дерева файлов Vue в каталоге pages
, например из следующего дерева файлов:
Автоматически сгенерирует следующую конфигурацию.
Итак, чтобы сгенерировать маршрут входа в систему, нам нужно создать файл frontend/pages/login.vue
и rontend/pages/account.vue
. В login.vue
нам нужно создать шаблон для форм, а также параметры данных для входной привязки и методы для отправки форм. Я также добавил обработку ошибок, чтобы мы могли отображать ошибки в форме. Для account.vue
page добавьте все, что хотите. В login.vue
добавьте следующее:
<template> <section class="container"> <form id="login" @submit.prevent="submit('login')"> <div v-if="errors.login"> <strong>Danger!</strong> {{ errors.login }} </div> <label for="login__email">Email Address</label> <input id="login__email" v-model="login.emailAddress" type="email" required> <label for="login__password">Password</label> <input id="login__password" v-model="login.password" type="password" required> <button type="submit">Submit</button> </form> <form id="register" @submit.prevent="submit('register')"> <div v-if="errors.register"> <strong>Danger!</strong> {{ errors.register }} </div> <label for="register__email">Email Address</label> <input id="register__email" v-model="register.emailAddress" type="email" required> <label for="register__full-name">Full Name</label> <input id="register__full-name" v-model="register.fullName" type="text" class="form-control" required> <label for="register__password">Password</label> <input id="register__password" v-model="register.password" type="password" class="form-control" required> <button type="submit" >Submit</button> </form> </section> </template> <script> export default { name: "Login", data() { return { // Set login form data login: { emailAddress: '', password: '', }, // Set register form data register: { emailAddress: '', fullName: '', password: '', }, // Set form errors errors: { login: '', register: '' } } }, methods: { submit(form) { const _this = this; _this.$store .dispatch('account/USER_' + form.toUpperCase() , this[form]) .then(res => { if (res.status === 200) _this.$router.push('/account'); }) .catch(error => _this.errors[form] = error.response.data.message ); } } } </script>
Теперь будут созданы представления для формы входа. Если вы сейчас перейдете к http: // localhost: 3000 / login, мы сможем использовать форму для входа и создания пользователя. Затем пользователь будет перенаправлен на созданный вами шаблон учетной записи, хотя, если вы обновите страницу, пользователь не будет установлен в вашем магазине.
Нам необходимо использовать файлы cookie сеанса, которые установлены в API, для этого мы должны использовать действие API user.check
для отправки пользовательских данных с сервера на сторону клиента, для этого нам нужно использовать nuxtServerInit
в нашем магазине. Сначала нам нужно добавить GET_USER
действие к нашему хранилищу учетных записей, в frontend/store/account.js
добавьте следующее:
GET_USER({commit}) { // Send request to check user against cookie return this.$axios.get('api/v1/user/check') .then(res => { // Mutate the user state with logged in user commit('SET_USER', res.data); return res; }) .catch(error => { // Mutate the user state to null commit('SET_USER'); return error; }) },
Затем нам нужно добавить действие nuxtServerInit
, открыть файл frontend/store/index.js
и добавить замену actions
следующим:
// Store Actions export const actions = { nuxtServerInit({dispatch}, {req}) { return new Promise((resolve, reject) => { // Reset Axios default headers this.$axios.defaults.headers.common = {}; // Match Axios default headers with request headers Object.keys(req.headers).map((key) => { this.$axios.defaults.headers.common[key] = req.headers[key] }); // dispatch GET_USER dispatch('account/GET_USER') .then(res => { resolve(true) }) .catch(error => { console.log('Provided token is invalid:', error); resolve(false) }); }); }, };
Это будет сбрасывать глухие заголовки Axios с заголовками в запросе, чтобы мы могли использовать серверную сторону файлов cookie на стороне клиента. Без этого файлы cookie не будут отправляться на сервер, поэтому он всегда будет возвращать, что пользователь не найден.
Наша единственная проблема сейчас заключается в том, что гостевой пользователь по-прежнему сможет перейти на страницу учетной записи, даже если он не вошел в систему. Чтобы предотвратить это, нам нужно создать isAuthenticated
Getter для нашей учетной записи как а также Промежуточное ПО, чтобы проверить, есть ли в хранилище приложений, аутентифицирован ли пользователь. Для этого в frontend/store/account.js
добавьте следующее:
// Account getters export const getters = { isAuthenticated(state) { return !!state.user }, loggedUser(state) { return state.user } };
И вам нужно будет создать файл backend/middleware/authenticated.js
и добавить следующее:
export default function ({store, redirect, route}) { // Get isAuthenticated getter from account store const isAuthenticated = store.getters['account/isAuthenticated']; // Test route to see if is login page or admin page. const isAdminUrl = /^\/admin|\/account(\/|$)/.test(route.fullPath); const isLoginUrl = /^\/login(\/|$)/.test(route.fullPath); // If user is authenticated and is login url if (isAuthenticated && isLoginUrl) // Redirect to account page return redirect('/account'); // If user is not authenticated and is an admin url else if (!isAuthenticated && isAdminUrl) // Redirect to login page return redirect('/login'); // Resolve promise return Promise.resolve() }
Затем нам необходимо добавить конфигурацию маршрутизатора в frontend/nuxt.config.js
, это выглядит следующим образом:
router: { middleware: 'authenticate' },
Теперь, если бы мы открыли страницу входа в систему как зарегистрированный пользователь, она перенаправила бы на страницу учетной записи, а если бы гость пытался получить доступ к URL-адресу под учетной записью или администратором, он бы перенаправил на страницу входа.
Заключение
Теперь у нас есть возможности для входа пользователя на сайт, проверка того, вошли ли они в систему на стороне сервера и функциональность, которая будет аутентифицировать маршруты и посмотреть, вошел ли пользователь в систему. Затем мы можем начать создавать представления, которые будут возможность создавать обновления и удалять наши модели!
Я бы рекомендовал вытащить серию GitHub Repository, как я комментировал в коде. Вы также можете следить за моими успехами в Instagram и Twitter.