Thứ năm, 12/12/2019 | 00:00 GMT+7

Cách thiết lập xác thực Vue.js và xử lý tuyến đường bằng vue-router

Vue.js là một khung JavaScript tiến bộ để xây dựng các ứng dụng front-end. Cùng với vue-router , ta có thể xây dựng các ứng dụng hiệu suất cao với các tuyến động hoàn chỉnh. Vue-router là một công cụ hiệu quả và có thể xử lý hiệu quả xác thực trong ứng dụng Vue của ta .

Trong hướng dẫn này, ta sẽ xem xét việc sử dụng vue-router để xử lý xác thực và kiểm soát truy cập cho các phần khác nhau của ứng dụng Vue.js của ta .

Bước 1 - Cài đặt Vue CLI và tạo ứng dụng

Để bắt đầu, hãy cài đặt Vue CLI và tạo ứng dụng Vue với nó:

  • npm install -g @vue/cli
  • npm install -g @vue/cli-init
  • vue init webpack vue-router-auth

Làm theo dấu nhắc cài đặt và hoàn tất cài đặt ứng dụng này. Nếu bạn không chắc chắn về một tùy chọn, hãy nhấp vào phím quay lại ( ENTER ) để tiếp tục với tùy chọn mặc định. Khi được yêu cầu cài đặt vue-router, hãy chấp nhận tùy chọn này, vì ta cần vue-router cho ứng dụng này.

Bước 2 - Cài đặt server Node.js

Tiếp theo, ta sẽ cài đặt một server Node.js sẽ xử lý xác thực cho ta . Đối với server Node.js của ta , ta sẽ sử dụng SQLite làm database được lựa chọn.

Chạy lệnh sau để cài đặt trình điều khiển SQLite:

  • npm install --save sqlite3

Bởi vì ta đang xử lý password , ta cần một cách để băm password . Ta sẽ sử dụng bcrypt để băm tất cả password của bạn . Chạy lệnh sau để cài đặt nó:

  • npm install --save bcrypt

Ta cũng muốn có một cách để xác nhận những user mà ta xác thực khi họ cố gắng thực hiện yêu cầu đối với một phần được bảo mật trong ứng dụng của ta . Đối với điều này, ta sẽ sử dụng JWT . Chạy lệnh sau để cài đặt gói JWT mà ta sẽ sử dụng:

  • npm install jsonwebtoken --save

Để đọc dữ liệu json , ta sẽ gửi đến server của bạn , ta cần body-parser . Chạy lệnh sau để cài đặt nó:

npm install --save body-parser 

Bây giờ mọi thứ đã được cài đặt xong, ta hãy tạo một server Node.js để xử lý xác thực user . Tạo một folder mới có tên là server . Đây là nơi ta sẽ lưu trữ mọi thứ ta sẽ sử dụng để tạo chương trình backend cho nút của ta .

Trong folder server , tạo một file và lưu nó dưới dạng app.js Thêm phần sau vào nó:

"use strict"; const express = require('express'); const DB = require('./db'); const config = require('./config'); const bcrypt = require('bcrypt'); const jwt = require('jsonwebtoken'); const bodyParser = require('body-parser');  const db = new DB("sqlitedb") const app = express(); const router = express.Router();  router.use(bodyParser.urlencoded({ extended: false })); router.use(bodyParser.json()); 

Ta đã yêu cầu tất cả các gói ta cần cho ứng dụng của bạn , xác định database và tạo server Express và bộ định tuyến.

Bây giờ, hãy xác định phần mềm trung gian CORS đảm bảo ta không gặp phải bất kỳ lỗi tài nguyên nguồn root chéo nào:

// CORS middleware const allowCrossDomain = function(req, res, next) {     res.header('Access-Control-Allow-Origin', '*');     res.header('Access-Control-Allow-Methods', '*');     res.header('Access-Control-Allow-Headers', '*');     next(); }  app.use(allowCrossDomain) 

Nhiều người sẽ sử dụng gói CORS ở đây, nhưng ta không có bất kỳ cấu hình phức tạp nào, vì vậy điều này là ổn.

Hãy xác định lộ trình đăng ký user mới:

router.post('/register', function(req, res) {     db.insert([         req.body.name,         req.body.email,         bcrypt.hashSync(req.body.password, 8)     ],     function (err) {         if (err) return res.status(500).send("There was a problem registering the user.")         db.selectByEmail(req.body.email, (err,user) => {             if (err) return res.status(500).send("There was a problem getting user")             let token = jwt.sign({ id: user.id }, config.secret, {expiresIn: 86400 // expires in 24 hours             });             res.status(200).send({ auth: true, token: token, user: user });         });      });  }); 

Có một vài điều đang xảy ra ở đây. Đầu tiên, ta chuyển phần thân yêu cầu đến một phương thức database (mà ta sẽ xác định sau) và truyền một hàm gọi lại để xử lý phản hồi từ hoạt động database . Như mong đợi, ta đã xác định các kiểm tra lỗi đảm bảo ta cung cấp thông tin chính xác cho user .

Khi user được đăng ký thành công, ta chọn dữ liệu user qua email và tạo mã thông báo xác thực cho user bằng gói jwt mà ta đã nhập trước đó. Ta sử dụng khóa bí mật trong file cấu hình của bạn (mà ta sẽ tạo sau) để ký thông tin xác thực. Bằng cách này, ta có thể xác minh mã thông báo được gửi đến server của ta và user không thể giả mạo danh tính.

Bây giờ, xác định lộ trình đăng ký administrator và đăng nhập, tương tự như đăng ký:

router.post('/register-admin', function(req, res) {     db.insertAdmin([         req.body.name,         req.body.email,         bcrypt.hashSync(req.body.password, 8),         1     ],     function (err) {         if (err) return res.status(500).send("There was a problem registering the user.")         db.selectByEmail(req.body.email, (err,user) => {             if (err) return res.status(500).send("There was a problem getting user")             let token = jwt.sign({ id: user.id }, config.secret, { expiresIn: 86400 // expires in 24 hours             });             res.status(200).send({ auth: true, token: token, user: user });         });      });  });  router.post('/login', (req, res) => {     db.selectByEmail(req.body.email, (err, user) => {         if (err) return res.status(500).send('Error on the server.');         if (!user) return res.status(404).send('No user found.');         let passwordIsValid = bcrypt.compareSync(req.body.password, user.user_pass);         if (!passwordIsValid) return res.status(401).send({ auth: false, token: null });         let token = jwt.sign({ id: user.id }, config.secret, { expiresIn: 86400 // expires in 24 hours         });         res.status(200).send({ auth: true, token: token, user: user });     }); }) 

Để đăng nhập, ta sử dụng bcrypt để so sánh password băm của ta với password do user cung cấp. Nếu chúng giống nhau, ta đăng nhập user . Nếu không, vui lòng phản hồi cho user theo cách bạn vui lòng.

Bây giờ, hãy sử dụng server Express để làm cho ứng dụng của ta có thể truy cập được:

app.use(router)  let port = process.env.PORT || 3000;  let server = app.listen(port, function() {     console.log('Express server listening on port ' + port) }); 

Ta đã tạo một server trên port: 3000 hoặc bất kỳ cổng nào được tạo động bởi hệ thống của ta .

Sau đó, tạo một file config.js trong cùng một folder và thêm thông tin sau vào đó:

module.exports = {     'secret': 'supersecret' }; 

Cuối cùng, tạo một file db.js và thêm những thứ sau vào đó:

"use strict"; const sqlite3 = require('sqlite3').verbose();  class Db {     constructor(file) {         this.db = new sqlite3.Database(file);         this.createTable()     }      createTable() {         const sql = `             CREATE TABLE IF NOT EXISTS user (                 id integer PRIMARY KEY,                  name text,                  email text UNIQUE,                  user_pass text,                 is_admin integer)`         return this.db.run(sql);     }      selectByEmail(email, callback) {         return this.db.get(             `SELECT * FROM user WHERE email = ?`,             [email],function(err,row){                 callback(err,row)             })     }      insertAdmin(user, callback) {         return this.db.run(             'INSERT INTO user (name,email,user_pass,is_admin) VALUES (?,?,?,?)',             user, (err) => {                 callback(err)             })     }      selectAll(callback) {         return this.db.all(`SELECT * FROM user`, function(err,rows){             callback(err,rows)         })     }      insert(user, callback) {         return this.db.run(             'INSERT INTO user (name,email,user_pass) VALUES (?,?,?)',             user, (err) => {                 callback(err)             })     } }  module.exports = Db 

Ta đã tạo một lớp cho database của ta để tóm tắt các chức năng cơ bản mà ta cần. Bạn có thể cần sử dụng các phương pháp chung hơn và có thể sử dụng lại ở đây cho các hoạt động database và có thể sử dụng một lời hứa để làm cho nó hiệu quả hơn. Điều này sẽ cho phép bạn có một repository mà bạn có thể sử dụng với tất cả các lớp khác mà bạn xác định (đặc biệt nếu ứng dụng của bạn sử dụng kiến trúc MVC và có bộ điều khiển).

Bước 3 - Cập nhật file vue-router

Có thể tìm thấy file vue-router trong folder ./src/router/ . Trong index.js , ta sẽ xác định tất cả các tuyến mà ta muốn ứng dụng của bạn có. Điều này khác với những gì ta đã làm với server của bạn và không nên nhầm lẫn.

Mở file và thêm thông tin sau:

import Vue from 'vue' import Router from 'vue-router' import HelloWorld from '@/components/HelloWorld' import Login from '@/components/Login' import Register from '@/components/Register' import UserBoard from '@/components/UserBoard' import Admin from '@/components/Admin'  Vue.use(Router) 

Ta đã nhập tất cả các thành phần mà ứng dụng của ta sẽ sử dụng. Ta sẽ tạo các thành phần sau.

Bây giờ, hãy xác định các tuyến đường cho ứng dụng của ta :

let router = new Router({     mode: 'history',     routes: [         {             path: '/',             name: 'HelloWorld',             component: HelloWorld         },         {             path: '/login',             name: 'login',             component: Login,             meta: {                  guest: true             }         },         {             path: '/register',             name: 'register',             component: Register,             meta: {                  guest: true             }         },         {             path: '/dashboard',             name: 'userboard',             component: UserBoard,             meta: {                  requiresAuth: true             }         },         {             path: '/admin',             name: 'admin',             component: Admin,             meta: {                  requiresAuth: true,                 is_admin : true             }         },     ] }) 

Bộ định tuyến Vue cho phép ta xác định meta trên các tuyến đường của ta để ta có thể chỉ định hành vi bổ sung. Trong trường hợp của ta ở trên, ta đã xác định một số tuyến là khách ( nghĩa là chỉ những user chưa được xác thực mới thấy nó), một số yêu cầu xác thực ( nghĩa là chỉ những user đã xác thực mới thấy nó) và tuyến cuối cùng chỉ admin-user mới có thể truy cập .

Bây giờ, hãy xử lý các yêu cầu đối với các tuyến đường này dựa trên đặc tả meta:

router.beforeEach((to, from, next) => {     if(to.matched.some(record => record.meta.requiresAuth)) {         if (localStorage.getItem('jwt') == null) {             next({                 path: '/login',                 params: { nextUrl: to.fullPath }             })         } else {             let user = JSON.parse(localStorage.getItem('user'))             if(to.matched.some(record => record.meta.is_admin)) {                 if(user.is_admin == 1){                     next()                 }                 else{                     next({ name: 'userboard'})                 }             }else {                 next()             }         }     } else if(to.matched.some(record => record.meta.guest)) {         if(localStorage.getItem('jwt') == null){             next()         }         else{             next({ name: 'userboard'})         }     }else {         next()      } })  export default router 

Vue-router có một phương thức beforeEach được gọi trước khi mỗi tuyến được xử lý. Đây là nơi ta có thể xác định điều kiện kiểm tra của bạn và hạn chế quyền truy cập của user . Phương thức nhận ba tham số - to , fromnext . to là nơi user có nhu cầu đi, from là nơi user đang đến từ đâu, và next là một chức năng gọi lại mà tiếp tục xử lý các yêu cầu user . Kiểm tra của ta là trên to phản đối.

Ta kiểm tra một số điều:

  • nếu route requiresAuth , hãy kiểm tra mã thông báo jwt cho thấy user đã đăng nhập.
  • nếu đường dẫn requiresAuth và chỉ dành cho admin-user , hãy kiểm tra xác thực và kiểm tra xem user có phải là administrator không
  • nếu tuyến đường yêu cầu guest , hãy kiểm tra xem user đã đăng nhập chưa

Ta chuyển hướng user dựa trên những gì ta đang kiểm tra. Ta sử dụng tên của tuyến đường để chuyển hướng, vì vậy hãy kiểm tra đảm bảo rằng bạn đang sử dụng tên này cho ứng dụng của bạn .

Cảnh báo: Luôn đảm bảo bạn đã gọi next() ở cuối mỗi điều kiện bạn đang kiểm tra. Điều này là để ngăn ứng dụng của bạn không bị lỗi trong trường hợp có một điều kiện mà bạn quên kiểm tra.

Bước 4 - Xác định một số thành phần

Để kiểm tra những gì ta đã xây dựng, hãy xác định một vài thành phần. Trong folder ./src/components/ , mở file HelloWorld.vue và thêm thông tin sau:

<template>     <div class="hello">         <h1>This is homepage</h1>         <h2>{{msg}}</h2>     </div> </template>  <script>     export default {         data () {             return {                 msg: 'Hello World!'             }         }     } </script>     <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped>     h1, h2 {         font-weight: normal;     }     ul {         list-style-type: none;         padding: 0;     }     li {         display: inline-block;         margin: 0 10px;     }     a {         color: #42b983;     } </style> 

Tạo một file mới Login.vue trong cùng một folder và thêm những thứ sau:

<template>     <div>         <h4>Login</h4>         <form>             <label for="email" >E-Mail Address</label>             <div>                 <input id="email" type="email" v-model="email" required autofocus>             </div>             <div>                 <label for="password" >Password</label>                 <div>                     <input id="password" type="password" v-model="password" required>                 </div>             </div>             <div>                 <button type="submit" @click="handleSubmit">                     Login                 </button>             </div>         </form>     </div> </template> 

Đó là đối với mẫu HTML. Bây giờ, hãy xác định đăng nhập xử lý tập lệnh:

<script>     export default {         data(){             return {                 email : "",                 password : ""             }         },         methods : {             handleSubmit(e){                 e.preventDefault()                 if (this.password.length > 0) {                     this.$http.post('http://localhost:3000/login', {                         email: this.email,                         password: this.password                     })                     .then(response => {                      })                     .catch(function (error) {                         console.error(error.response);                     });                 }             }         }     } </script> 

Đến đây, ta có các thuộc tính dữ liệu emailpassword liên kết với các trường biểu mẫu để thu thập thông tin đầu vào của user . Ta đã yêu cầu server xác thực thông tin xác thực mà user cung cấp.

Bây giờ, hãy sử dụng phản hồi từ server :

[...] methods : {             handleSubmit(e){                 [...]                     .then(response => {                         let is_admin = response.data.user.is_admin                         localStorage.setItem('user',JSON.stringify(response.data.user))                         localStorage.setItem('jwt',response.data.token)                          if (localStorage.getItem('jwt') != null){                             this.$emit('loggedIn')                             if(this.$route.params.nextUrl != null){                                 this.$router.push(this.$route.params.nextUrl)                             }                             else {                                 if(is_admin== 1){                                     this.$router.push('admin')                                 }                                 else {                                     this.$router.push('dashboard')                                 }                             }                         }                     })                    [...]                 }             }         }     } 

Ta lưu trữ các jwt token và user thông tin trong localStorage vì vậy ta có thể truy cập nó từ tất cả các phần của ứng dụng của ta . Ta chuyển hướng user đến bất kỳ phần nào trong ứng dụng của ta mà họ đã cố gắng truy cập trước khi được chuyển hướng đăng nhập. Nếu họ đến folder đăng nhập, ta sẽ chuyển hướng họ dựa trên kiểu user .

Tiếp theo, tạo file Register.vue và thêm các thông tin sau vào đó:

<template>     <div>         <h4>Register</h4>         <form>             <label for="name">Name</label>             <div>                 <input id="name" type="text" v-model="name" required autofocus>             </div>              <label for="email" >E-Mail Address</label>             <div>                 <input id="email" type="email" v-model="email" required>             </div>              <label for="password">Password</label>             <div>                 <input id="password" type="password" v-model="password" required>             </div>              <label for="password-confirm">Confirm Password</label>             <div>                 <input id="password-confirm" type="password" v-model="password_confirmation" required>             </div>              <label for="password-confirm">Is this an administrator account?</label>             <div>                 <select v-model="is_admin">                     <option value=1>Yes</option>                     <option value=0>No</option>                 </select>             </div>              <div>                 <button type="submit" @click="handleSubmit">                     Register                 </button>             </div>         </form>     </div> </template> 

Bây giờ, xác định đăng ký xử lý tập lệnh:

<script>     export default {         props : ["nextUrl"],         data(){             return {                 name : "",                 email : "",                 password : "",                 password_confirmation : "",                 is_admin : null             }         },         methods : {             handleSubmit(e) {                 e.preventDefault()                  if (this.password === this.password_confirmation && this.password.length > 0)                 {                     let url = "http://localhost:3000/register"                     if(this.is_admin != null || this.is_admin == 1) url = "http://localhost:3000/register-admin"                     this.$http.post(url, {                         name: this.name,                         email: this.email,                         password: this.password,                         is_admin: this.is_admin                     })                     .then(response => {                         localStorage.setItem('user',JSON.stringify(response.data.user))                         localStorage.setItem('jwt',response.data.token)                          if (localStorage.getItem('jwt') != null){                             this.$emit('loggedIn')                             if(this.$route.params.nextUrl != null){                                 this.$router.push(this.$route.params.nextUrl)                             }                             else{                                 this.$router.push('/')                             }                         }                     })                     .catch(error => {                         console.error(error);                     });                 } else {                     this.password = ""                     this.passwordConfirm = ""                      return alert("Passwords do not match")                 }             }         }     } </script> 

Cấu trúc này tương tự như file Login.vue . Nó tạo thành phần đăng ký và phương thức đi kèm để xử lý việc user gửi biểu mẫu đăng ký.

Bây giờ, tạo file Admin.vue và thêm file sau:

<template>     <div class="hello">         <h1>Welcome to administrator page</h1>         <h2>{{msg}}</h2>     </div> </template>  <script>     export default {         data () {             return {                 msg: 'The superheros'             }         }     } </script> <style scoped>     h1, h2 {         font-weight: normal;     }     ul {         list-style-type: none;         padding: 0;     }     li {         display: inline-block;         margin: 0 10px;     }     a {         color: #42b983;     } </style> 

Đây là thành phần ta sẽ mount khi user truy cập trang quản trị.

Cuối cùng, tạo file UserBoard.vue và thêm những thứ sau:

<template>     <div class="hello">         <h1>Welcome to regular users page</h1>         <h2>{{msg}}</h2>     </div> </template>  <script>     export default {         data () {             return {                 msg: 'The commoners'             }         }     } </script>  <!-- Add "scoped" attribute to limit CSS to this component only --> <style scoped>     h1, h2 {         font-weight: normal;     }     ul {         list-style-type: none;         padding: 0;     }     li {         display: inline-block;         margin: 0 10px;     }     a {         color: #42b983;     } </style> 

Đây là file ta sẽ thấy khi user truy cập trang tổng quan.

Bước 5 - Cài đặt Axios trên phạm vi global

Đối với tất cả các yêu cầu server của ta , ta sẽ sử dụng axios . Axios là một ứng dụng HTTP dựa trên lời hứa cho trình duyệt và Node.js.

Chạy lệnh sau để cài đặt axios:

  • npm install --save axios

Để làm cho nó có thể truy cập được trên tất cả các thành phần của ta , hãy mở file ./src/main.js và thêm thông tin sau:

import Vue from 'vue' import App from './App' import router from './router' import Axios from 'axios'  Vue.prototype.$http = Axios;  Vue.config.productionTip = false  new Vue({     el: '#app',     router,     components: { App },     template: '<App/>' }) 

Bằng cách xác định Vue.prototype.$http = Axios ta đã sửa đổi công cụ Vue và thêm axios. Bây giờ ta có thể sử dụng axios trong tất cả các thành phần của ta như thế this.$http .

Bước 6 - Chạy ứng dụng

Bây giờ ta đã hoàn thành ứng dụng, ta cần xây dựng tất cả các tài sản của bạn và chạy nó. Bởi vì ta có một server Node.js cùng với ứng dụng Vue của ta , ta cần cả hai để ứng dụng của ta hoạt động.

Hãy thêm một tập lệnh sẽ giúp ta chạy server Node của bạn . Mở file package.json và thêm thông tin sau:

[...] "scripts": {     "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",     "start": "npm run dev",     "server": "node server/app",     "build": "node build/build.js"   }, [...] 

Ta đã thêm tập lệnh server để giúp ta khởi động server nút. Bây giờ, hãy chạy lệnh sau để khởi động server :

  • npm run server

Sau đó, tạo một version terminal khác và chạy ứng dụng Vue như sau:

  • npm run dev

Điều này sẽ xây dựng tất cả các tài sản và khởi động ứng dụng. Bạn có thể mở liên kết mà nó hiển thị cho bạn để xem ứng dụng.

Kết luận

Trong hướng dẫn này, ta đã sử dụng vue-router để xác định các kiểm tra trên các tuyến đường của ta và ngăn user truy cập các tuyến đường nhất định. Ta cũng đã biết cách chuyển hướng user đến các phần khác nhau của ứng dụng dựa trên trạng thái xác thực. Cuối cùng, ta đã xây dựng một server mini với Node.js để xử lý xác thực user .

Những gì ta đã làm là một ví dụ về cách kiểm soát truy cập được thiết kế trong các khung như Laravel. Bạn có thể kiểm tra vue-router và xem bạn có thể làm gì khác với nó.


Tags:

Các tin liên quan