javascript
javascript --- [express+ vue2.x + elementUI]登陆的流程梳理
說明
涉及到以下知識點:
- 登陸的具體流程
- express、vue2.x、elementUI、axios、jwt、assert 登陸方面的API使用
- 中間件的使用
- 前后端通過http狀態碼,進行響應的操作(這里主要是401)
- 密碼驗證(bcrypt的hashSync方法對明文密碼進行加密,compareSync方法對加密的密碼進行驗證)
- token的使用(后端jwt.sign生成token, 前端使用瀏覽器緩存存儲token,后端驗證token)
登錄
界面
使用Vue2.x + elementUI實現的登錄界面
<template><div class="login-container"><el-card header="請先登錄" class="login-card"><!-- @submit.native.prevent阻止表單的默認提交行為,并將提交的事件處理函數,綁定到login上 --><el-form @submit.native.prevent="login"><el-form-item label="用戶名"><el-input v-model="model.username"></el-input></el-form-item><el-form-item label="密碼"><el-input type="password" v-model="model.password"></el-input></el-form-item><el-form-item><el-button type="primary" native-type="submit">登錄</el-button></el-form-item></el-form></el-card></div> </template>邏輯
- 前端傳入用戶名和密碼
- 后端得到數據后,與數據庫進行對比
- 根據用戶名,查找數據庫中的用戶信息
- 對密碼使用bcrypt的對比操作
- 通過驗證后,返回一個token
注意: 上面的jwt.sign接收2個參數,第一個應該是作為區分的一個對象.如用戶的id. 第二個是一個密鑰字符串.在express中使用app.set(‘secret’, ‘Marron’),將密鑰保存在全局app中. 之后使用app.get(‘secret’)獲取該密鑰.
jwt.sign返回一個散列值,就是我們需要的token
異常處理
http響應并不總是成功的,比如在登錄這一塊.用戶名或密碼很容易不成功.這個時候就會返回一個403 forbidden,其中一個比較好的解決方案是: 使用axios的攔截器,對http的返回進行攔截. 若發生錯誤,使用Vue原型上面的$message.error(前面已經使用elementUI掛載了)方法給出錯誤提示
// admin/src/http.js import axios from 'axios' import Vue from 'vue'const http = axios.create({baseURL: 'http://localhost:3000/admin/api' })// 攔截返回的http http.interceptors.response.use(res=>{// http響應是成功的return res},err=>{if(err.message.response.data.message){// http響應失敗.使用Vue原型上面的方法彈出錯誤Vue.prototype.$message.error({type: 'error',message: err.message.response.data.message})return Promise.reject(err)}} )前端得到token
登錄驗證
前端請求添加token
如果用戶登錄了,那么在瀏覽器的localStorage中必然會保存token.在發送登錄請求給后端時,需要帶上這個token.在axios中使用全局的請求攔截(http.interceptors.request.use)來實現這個功能
const http = axios.create({baseURL: 'http://localhost:3000/admin/api' }) http.interceptors.request.use(config => {if(localStorage.token) {// 給請求頭部加tokenconfig.headers.Authorization = 'Bearer ' + localStorage.token}return config},err => {return Promise.reject(err)} ) // 在使用`config.headers.Authorization`之后,每次http請求都會附帶一個 Authorization 請求頭. // Authorization值的最前面加 'Bearer '的原因是為了符合規范在添加好了對所有路由的前端請求攔截后,如果因為登錄原因,出現的錯誤.后端一般返回的是401狀態碼,這個時候,需要跳轉到登陸頁面,下面對狀態碼 401 的返回值進行處理
const http = axios.create({baseURL: 'http://localhost:3000/admin/api' }) http.interceptors.response.use(res => { return res},err => {// 這里處理報錯if(err.response.data.message){Vue.prototype.$message.error({type: 'error',message: err.response.data.message})// 處理401狀態碼: 跳轉到登陸頁面if(err.response.status == 401) router.push('/login')}} )后端解析請求頭,驗證token
以上實現了前端在發送http請求時,攜帶token(放在Authorization請求頭部中),后端需要在前端通過URL請求非登陸接口時,判斷用戶是否登錄.可以寫一個登陸驗證的中間件. 如果在對正常的路徑進行處理之前,先通過中間件驗證.
中間件的邏輯如下:
- 首先通過req.headers.authorization獲取token,若無token則設置為 ''
- 若token存在則繼續下一步,否則使用assert拋出異常
- 然后使用jwt驗證token.得到解碼后的id
- 若存在id,則證明token沒有被篡改,繼續下一步,否則assert拋出異常
- 最后根據id在數據庫中查詢user.并將user賦給req.user.
- 若存在req.user則跳轉到下一個中間件,否則使用assert拋出異常
以上提供了一個中間件: 它判斷token是否存在(正確),若不正確則拋出異常.若正確則繼續下一個中間件.在主路由中導入.并在需要的地方添加這個中間件
// server/router/admin/index.js module.exports = app => {const express = require('express')const authMiddleware = require('../../middleware/auth')const router = express.router({mergeParams: true})app.use('/admin/api/rest/:resource', authMiddleware(), router) }上面使用了assert拋出異常,因此還需要一個錯誤捕捉中間件,放在所有路由的最后,用于捕捉錯誤,它會將捕獲到的異常,作為參數傳遞給前端.這樣前端就能根據狀態碼做出響應的處理了
// server/router/admin/index.js module.exports = app => {const express = require('express')const authMiddleware = require('../../middleware/auth')const router = express.router({mergeParams: true})// 放到所有路由的后面app.use(async (err, req, res, next)=>{console.log(err)res.status(err.statesCode || 500).send({ message: err.message})}) }前端路由校驗
上面已經完成了,在發送Http請求時,進行路由校驗.若401則跳轉到登陸頁面.但是,那些不需要HTTP請求的網頁還是可以不需要登陸就能直接訪問.下面有必要做前端的路由校驗
【具體實現如下】:
- 將不需要登陸的就能訪問的(主要是是Login組件)路由,添加一個{isPublic: true}屬性
- 然后使用全局前置守衛,在進入路由前判斷localStorage中是否存在token.若存在,則進行下一步,否則跳轉到登陸頁面. 而登陸頁面設置了公開訪問屬性,因此不會觸發全局前置守衛
在主函數中加載路由,并渲染更新
// admin/src/main.js import Vue from 'vue' import App from './App.vue' import './plugins/element.js' import router from './router'import './style.css'Vue.config.productionTip = falsenew Vue({router,render: h => h(App) }).$mount('#app') 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的javascript --- [express+ vue2.x + elementUI]登陆的流程梳理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c盘瘦身(c盘瘦身最简单的方法win10
- 下一篇: 线程启动语句的顺序是否决定线程的执行次序