日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

javascript --- [express+ vue2.x + elementUI]登陆的流程梳理

發布時間:2023/12/10 javascript 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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>

邏輯

  • 前端傳入用戶名和密碼
<template><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 v-model="model.password" type="password"></el-input></el-form-item></el-form> </template> <script>export default {data(){return {model: {}}},methods:{async login(){// post提交數據,返回的是一個tokenconst res = await this.$http.post('login', this.model)}}} </script>
  • 后端得到數據后,與數據庫進行對比
    • 根據用戶名,查找數據庫中的用戶信息
    • 對密碼使用bcrypt的對比操作
  • 通過驗證后,返回一個token
app.post('/admin/api/login', async(req, res)=>{const { username, password } = req.bodyconst AdminUser = require('../../models/AdminUser')// 根據用戶名 查找數據庫中的用戶信息const user = await AdminUser.findOne({username}).select('+password')if(!user) return res.status(422).send({message:'用戶名不存在'})// 走到這里,用戶查找到了const isValid = password && user.password && require('bcrypt').compareSync(password, user.password)if(!isValid) return res.status(422).send({ message:'密碼錯誤'}) // 到這里就使用jwt生成token并返回了// 首先需要安裝: npm i jsonwebtokenconst token = jwt.sign({id: username._id}, app.get('secret'))res.send({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中,首先將其保存在瀏覽器緩存中(sessionStorage或localStorage)
  • 然后跳轉到首頁,在vue中使用this.$router.push('/')
  • 彈出提示框,登錄成功, 在vue2.x + elementUI中使用this.$message({ type:'success', message:'登錄成功'})
  • <template><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 v-model="model.password" type="password"></el-input></el-form-item></el-form> </template> <script>export default {data(){return {model: {}}},methods:{async login(){// post提交數據,返回的是一個tokenconst res = await this.$http.post('login', this.model)// 將token存入localStorage中(前端磁盤),瀏覽器關閉了,下次還能訪問到localStorage.token = res.data.token// 跳轉到首頁this.$router.push('/')// 彈出登錄成功this.$message({type: 'success',message: '登錄成功'})}}} </script>

    登錄驗證

    前端請求添加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拋出異常
    // sever/middleware/auth.js module.exports = options =>{const assert = require('http-assert') // 簡化代碼const jwt = require('jsonwebtoken') // 用于將token密文解析為明文const AdminUser = require('../models/AdminUser') // 獲取AdminUser模型return async(req, res, next)=>{// 獲取tokenconst token = String(req.headers.authorization || '').split(' ').pop()assert(token, 401, '請先登陸') // 這里若無token: 則代表未登陸const {id} = jwt.verify(token, req.app.get('secret'))assert(id, 401, '請先登陸') // 這里若無id: 則代表token過期或被篡改了req.user = AdminUser.findById(id)assert(req.user, 401, '請先登錄') // 這里若沒用找到user, 則代表給的是假idawait next()} }

    以上提供了一個中間件: 它判斷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/router/index.js import Vue from 'vue' import VurRouter from 'vue-router' const routes = [{ path: '/login',name: 'login',component: Login,meta: { isPublic: true}},{path: '/',name: 'main',component: Main,children: [ ... ]} ] const router = new VueRouter({routes })router.beforeEach((to, from, next) =>{if(!to.meta.isPublic && localStorage.token){return next('/login')}next() }) export default router

    在主函數中加載路由,并渲染更新

    // 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]登陆的流程梳理的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。