
vue-cli with the webpack template. Referring to the Vue tutorial, you can find out that vue-cli are used to install vue-cli and prepare the working environment: # vue-cli $ npm install --global vue-cli # "webpack" $ vue init webpack my-project # $ cd my-project $ npm install $ npm run dev application folder in its root directory. You can also skip this step by creating a folder while working with vue-cli . If you decide not to create a folder, then you need to give the project a name by running a command like this: vue init webpack name-of-your-project application folder:
vue-cli is not yet installed, run the following command: npm i --g vue-cli vue-cli globally, so it does not matter which folder we will be in by executing it. vue init webpack application folder that has already been created to host the application.
application folder, install the dependencies and run the project. npm i npm run dev 
application/src/assets folder and delete logo.png , since we will not use this file. Next, open the file of the root component App.vue from the application/src folder and bring it to the form represented by the following code fragment: <template> <div id="app"> <v-container> <router-view/> </v-container> </div> </template> <script> export default { name: 'app' } </script> index.js file in the router folder and bring it to this form: import Vue from 'vue' import Router from 'vue-router' Vue.use(Router) export default new Router({ routes: [ {} ] }) HelloWorld.vue file from the components folder.application folder: npm i --save axios vuetify vue-cookie npm i --save-dev sass-loader node-sass axios to handle HTTP requests. In vuetify we are interested in visual components and the ability to use a grid-based layout. We will use the vue-cookie library to work with cookies. The sass-loader and node-sass allow us to use SCSS.components folder and create the pages folder in it, in which we will create the Authentication folder. In this folder, you need to create an Authentication.vue file representing the component that will be used for authentication. This is what should end up:
Authentication.vue file we place the following code: <template> <h1>Auth!</h1> </template> <script> export default {} </script> router folder and work with the routes.Authentication component and configure a route to use it: import Vue from 'vue' import Router from 'vue-router' // Pages import Authentication from '@/components/pages/Authentication/Authentication' Vue.use(Router) export default new Router({ routes: [ { path: '/login', name: 'Authentication', component: Authentication } ] }) main.js file from the src folder and import the vuetify and vue-cookie : import VueCookie from 'vue-cookie' import Vuetify from 'vuetify' import('../node_modules/vuetify/dist/vuetify.min.css') Vue.use(VueCookie) Vue.use(Vuetify) Vue.config.productionTip = false App.vue to the App.vue component from the src folder and look at the styles. First you need to prepare the style tag. Post it immediately after closing the script tag: <style lang="scss"> </style> src/assets folder and create the styles.scss file and the partials folder in it. In this folder, create two partial templates, represented by the files _variables.scss and _animations.scss . The result should be the following structure:
_variables.scss file _variables.scss we will set the following parameters: // Colors $background-tint: #1734C1; $background-color: rgba(0, 0, 0, .5); _animations.css file _animations.css add the bounceIn and slideInFromLeft animation descriptions: @keyframes bounceIn { to { animation-timing-function: cubic-bezier(.215, .61, .355, 1) } 0% { opacity: 0; transform: scale3d(.3, .3, .3) } 20% { transform: scale3d(1.1, 1.1, 1.1) } 40% { transform: scale3d(.9, .9, .9) } 60% { opacity: 1; transform: scale3d(1.03, 1.03, 1.03) } 80% { transform: scale3d(.97, .97, .97) } to { opacity: 1; transform: scaleX(1) } } @keyframes slideInFromLeft { from { transform: translateX(-2500px); opacity: 0 } 50% { transform: translateX(0); opacity: 1; } 70% { transform: translateX(-20px); } 90% { transform: translateX(10px); } to { transform: translateX(0); } } styles.scss : @import "./partials/variables"; @import "./partials/animations"; assets folder, create an images folder. Here you can put any image that will be used as a background. Here , in the repository, you can find the image that is used in this material.App.vue styling block in the App.vue file to the following view: <style lang="scss"> @import "./assets/styles"; body { background: url('./assets/images/background.jpg') no-repeat center center fixed; &:after { content: ''; position: fixed; width: 100%; height: 100%; top: 0; left: 0; background-color: $background-tint; opacity: .3; z-index: -1; } } </style> body :after pseudo-element, we set the background-color parameter by writing the value of the $background-tint variable to it. This will apply a magenta color filter to the background image. Here are the different versions of the background image.
index.html file, which is located in the application folder, and add the following to the head tag: <meta name="viewport" content="initial-scale=1"> <link href='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons' rel="stylesheet"> Authentication component. Create an index.js file in the Authentication folder.
import Axios from 'axios' import router from '@/router' const BudgetManagerAPI = `http://${window.location.hostname}:3001` Authentication object that will contain the methods we need: export default { user: { authenticated: false } } user , which stores information about whether the user is authenticated. import Axios from 'axios' import router from '@/router' const BudgetManagerAPI = `http://${window.location.hostname}:3001` export default { user: { authenticated: false }, authenticate (context, credentials, redirect) { Axios.post(`${BudgetManagerAPI}/api/v1/auth`, credentials) .then(({data: {token}}) => { context.$cookie.set('token', token, '1D') context.validLogin = true this.user.authenticated = true if (redirect) router.push(redirect) }).catch(({response: {data}}) => { context.snackbar = true context.message = data.message }) }, signup (context, credentials, redirect) { Axios.post(`${BudgetManagerAPI}/api/v1/signup`, credentials) .then(({data: {token}}) => { context.$cookie.set('token', token, '1D') context.validSignUp = true this.user.authenticated = true if (redirect) router.push(redirect) }).catch(({response: {data}}) => { context.snackbar = true context.message = data.message }) }, checkAuthentication () { const token = document.cookie if (token) this.user.authenticated = true else this.user.authenticated = false }, getAuthenticationHeader (context) { return `Bearer ${context.$cookie.get('token')}` } } context : this is a component of Vue.credentials : there will be a username ( username ) and password ( password ).redirect : here will be the path we are going to redirect the user to.credentials argument passed. Then we unstructure the response, data , since here we are only interested in the value of token , we save this value in the cookie and set the lifetime of this data to be one day. We also set the validLogin variable and the authenticated value of the user object to true , and finally, redirect the user along the path from the redirect argument.context field's snackbar field to true and write an error message to the message.Authorization header.Authentication.vue file. Here we will use the tools Vuetify: <template> <div class="l-auth-container"> <div class="l-auth"> <v-form v-model="validLogin"> <v-text-field label="Username" v-model="credentials.username" prepend-icon="account_box" :rules="rules" required color="light-blue lighten-1"> </v-text-field> <v-text-field label="Password" v-model="credentials.password" prepend-icon="lock" :rules="rules" :append-icon="loginPasswordVisible ? 'visibility' : 'visibility_off'" :append-icon-cb="() => (loginPasswordVisible = !loginPasswordVisible)" :type="loginPasswordVisible ? 'text' : 'password'" color="light-blue lighten-1" required> </v-text-field> <v-btn flat color="light-blue lighten-1" @click.native="signUpVisible = true">Create account</v-btn> <v-btn color="light-blue lighten-1" @click.native="submitAuthentication()">Login</v-btn> </v-form> </div> <div class="l-signup" v-if="signUpVisible"> <v-form v-model="validSignUp"> <v-text-field label="Username" v-model="newUser.username" prepend-icon="account_box" :rules="rules" required color="light-blue lighten-1"> </v-text-field> <v-text-field label="Password" v-model="newUser.password" prepend-icon="lock" :rules="rules" :append-icon="signUpPasswordVisible ? 'visibility' : 'visibility_off'" :append-icon-cb="() => (signUpPasswordVisible = !signUpPasswordVisible)" :type="signUpPasswordVisible ? 'text' : 'password'" color="light-blue lighten-1" required> </v-text-field> <v-btn block color="light-blue lighten-1" @click.native="submitSignUp()">Sign Up</v-btn> </v-form> </div> <v-snackbar timeout="6000" bottom="bottom" color="red lighten-1" v-model="snackbar"> {{ message }} </v-snackbar> </div> </template> div element with the class l-auth-container , which acts as a container. Next comes another div with the l-auth class, which contains the structure of the elements for organizing the input form, in particular, this is the v-form element bound to the validLogin variable.v-text-field input fields that are bound to data from the credentials (we will deal with this data below). The fields are equipped with icons taken from https://material.io/icons/ , the input validation rules are associated with them (both here and there are the same rules, we will not complicate the project), besides, both of these fields are mandatory.loginPasswordVisible from true to false and vice versa. If this variable is set to true , then the type parameter of the input field is set to text , otherwise it is a password .signUpVisible set to true . The device of this form is similar to the device of the login form, only a few lines are changed here. In particular, the variable signUpPasswordVisible is used instead of loginPasswordVisible and another button click handling method.v-snackbar , which, during authentication, is used to display messages.Authentication.vue file, we describe the component script: <script> import Authentication from '@/components/pages/Authentication' export default { data () { return { snackbar: false, validLogin: false, validSignUp: false, signUpVisible: false, loginPasswordVisible: false, signUpPasswordVisible: false, rules: [ (value) => !!value || 'This field is required' ], credentials: { username: '', password: '' }, newUser: { username: '', password: '' }, message: '' } }, methods: { submitAuthentication () { Authentication.authenticate(this, this.credentials, '/') }, submitSignUp () { Authentication.signup(this, this.newUser, '/') } } } </script> index.js file from the Authentication folder, since we need the authenticate method defined inside this file.snackbar : used for message bar.validLogin : used to validate the login form.validSignUp : used to validate the registration form.signUpVisible : used to display the registration form (when set to true ).loginPasswordVisible : indicates whether the user can see the password entered on the login form.signUpPasswordVisible : indicates whether the password entered in the registration form can be seen.rules : rules for checking data entered in form fields.credentials : an object bound to the input fields of the login form used to authenticate the user.newUser : an object newUser with the input fields of the registration form in the system.message : used to display messages during authentication.submitAuthentication method calls the authenticate method from the Authentication file, passing context, credentials, and redirection paths. The submitSignUp method submitSignUp used to call the signup method.Authentication.vue file (here you can unleash the imagination and do everything the way you want): <style lang="scss"> @import "./../../../assets/styles"; .l-auth { background-color: $background-color; padding: 15px; margin: 45px auto; min-width: 272px; max-width: 320px; animation: bounceIn 1s forwards ease; } .l-signup { background-color: $background-color; padding: 15px; margin: 45px auto; min-width: 272px; max-width: 320px; animation: slideInFromLeft 1s forwards ease; } </style> 
pages folder and create the Home.vue component Home.vue :
<template> <div> <h3>Hi! this is our App's Home</h3> <ul> <li v-if="users != null" v-for="user in users"> {{ user.username }} </li> </ul> </div> </template> <script> import Axios from 'axios' import Authentication from '@/components/pages/Authentication' const BudgetManagerAPI = `http://${window.location.hostname}:3001` export default { data () { return { users: [] } }, mounted () { this.getAllUsers() }, methods: { getAllUsers (context) { Axios.get(`${BudgetManagerAPI}/api/v1/users`, { headers: { 'Authorization': Authentication.getAuthenticationHeader(this) } }).then(({data}) => (this.users = data)) } } } </script> 
index.js file from the router folder. Here is what kind of it needs to lead: import Vue from 'vue' import Router from 'vue-router' import * as Auth from '@/components/pages/Authentication' // Pages import Home from '@/components/pages/Home' import Authentication from '@/components/pages/Authentication/Authentication' Vue.use(Router) const router = new Router({ routes: [ { path: '/', name: 'Home', component: Home, meta: { requiredAuth: true } }, { path: '/login', name: 'Authentication', component: Authentication } ] }) router.beforeEach((to, from, next) => { if (to.meta.requiredAuth) { if (Auth.default.user.authenticated) { next() } else { router.push('/login') } } else { next() } }) export default router import * as Auth from '@/components/pages/Authentication' Authentication file, calling it Auth , since the Authentication component has also been imported. const router = new Router({ routes: [ { path: '/', name: 'Home', component: Home, meta: { requiredAuth: true } }, { path: '/login', name: 'Authentication', component: Authentication } ] }) Router object in order to create a navigation system protection later. We also add the path to the Home component. The meta.requiredAuth parameter will be meta.requiredAuth to true . This means that if an unauthenticated user tries to access this component, it will be redirected to the login page. router.beforeEach((to, from, next) => { if (to.meta.requiredAuth) { if (Auth.default.user.authenticated) { next() } else { router.push('/login') } } else { next() } }) meta.requiredAuth parameter is meta.requiredAuth to true . If so, we check the user object from Authentication . If the user is not authenticated, we redirect him to the login page. export default router main.js file in the application folder. Here we are going to import the Authentication file and call the checkAuthentication method: import Vuetify from 'vuetify' import Authentication from '@/components/pages/Authentication' import('../node_modules/vuetify/dist/vuetify.min.css') Vue.use(VueCookie) Vue.use(Vuetify) Vue.config.productionTip = false Authentication.checkAuthentication() Source: https://habr.com/ru/post/340926/
All Articles