vue項(xiàng)目中存儲(chǔ)與使用后端傳遞過(guò)來(lái)的token
前言
以前一直都是在postman中測(cè)試驗(yàn)證token,現(xiàn)在用在真正的項(xiàng)目中,記錄一下在vue項(xiàng)目中token的存儲(chǔ)和使用
后端關(guān)于token的設(shè)置
app.js中需要設(shè)置token的地方
const expressJWT = require('express-jwt') const app = express(); const config = require('./config') app.use(expressJWT({secret: config.jwtSecretKey}).unless({path: [/^\/api\/users/]})) const testRouter = require('./routes/testToken') app.use('/my', testRouter)
config中就是一個(gè)秘鑰,我單獨(dú)寫(xiě)了一個(gè)文件,不再放上來(lái)了
unless后面是不需要token的地址,也就是以/api/users開(kāi)頭的鏈接都不需要token驗(yàn)證
用到的testToken.js如下:
const express = require('express'); const router = express.Router(); const test = require('../router_handler/testToken') router.get('/current', test.test) module.exports = router
使用模塊化的寫(xiě)法,真正的路由處理函數(shù)寫(xiě)在/router_handler/testToken.js中,內(nèi)容如下:
const db = require('../db/index'); exports.test = (req, res) => { const sql = 'select * from users where id = ?' db.query(sql, req.user.id, (err, results) => { if(err) return res.send({status: 404, message: err}) if(results.length !== 1) return res.send({status: 404, messsage: '獲取用戶(hù)信息失敗,需重新登錄'}) res.json(results[0]) }) // res.send(req) }
實(shí)際上就是一個(gè)獲取用戶(hù)信息的處理函數(shù),在mysql中根據(jù)id查詢(xún)用戶(hù)信息
注意,重點(diǎn)來(lái)了,經(jīng)過(guò)上述一系列設(shè)置后,當(dāng)我們?cè)L問(wèn)非/api/users開(kāi)頭的鏈接的時(shí)候,都需要驗(yàn)證,也就是在請(qǐng)求參數(shù)中提供token,而這個(gè)token則是在登錄的時(shí)候給出的,我寫(xiě)在用戶(hù)登錄的處理函數(shù)中user.js,如下
// 用戶(hù)登錄的處理函數(shù) exports.login = (req, res) => { const userinfo = req.body const sql = 'select * from users where name = ?' db.query(sql, userinfo.name, (err, results) => { if(err) return res.send({status: 404, message: err.message}) if(results.length !== 1) return res.status(404).json('用戶(hù)不存在!') const compareResults = bcrypt.compareSync(userinfo.password, results[0].password) if(!compareResults) return res.status(404).json('密碼錯(cuò)誤!') const user = { id: results[0].id, name: results[0].name, avatar: results[0].avatar, identify: results[0].identify } const tokenStr = jwt.sign(user, config.jwtSecretKey, {expiresIn: '10h'}) res.json({ status:200, message: '登錄成功', // result: results[0], token: 'Bearer ' + tokenStr }) }) }
不相關(guān)的代碼我就不寫(xiě)了,注意看到tokenStr這個(gè)變量,就是存儲(chǔ)的token值,通過(guò)res響應(yīng)出來(lái)。
總結(jié)一下,后端存儲(chǔ)token的流程:
- 編寫(xiě)登錄函數(shù),向頁(yè)面響應(yīng)token字符串;
- 入口文件中(app.js)設(shè)置需要提供token的路由,并提供解析token字符串的秘鑰;
- 編寫(xiě)對(duì)應(yīng)的路由函數(shù),處理請(qǐng)求
至此,后端的關(guān)鍵要點(diǎn)已經(jīng)寫(xiě)完了,進(jìn)入前端token的存儲(chǔ)
前端頁(yè)面取用token
前端頁(yè)面在登錄的時(shí)候,應(yīng)該把后端響應(yīng)過(guò)來(lái)的token存儲(chǔ)起來(lái),這樣就可以實(shí)現(xiàn)路由守護(hù)和免登陸的功能
token存儲(chǔ)
通過(guò)ajax請(qǐng)求路由地址,并訪(fǎng)問(wèn)res.data中的token字符串,并存儲(chǔ)在瀏覽器中,步驟和寫(xiě)法是固定的
我寫(xiě)在Login.vue中,如下:
methods: { submitForm(formName) { this.$refs[formName].validate(valid => { if (valid) { this.$axios .post("/users/login", this.loginUser) .then(res => { // console.log(res) //token const { token } = res.data localStorage.setItem("eleToken", token) this.$router.push("/index"); }); } else { console.log("error submit!!"); return false; } }); } }
const { token } = res.data
通過(guò)解構(gòu)賦值的方式取出響應(yīng)數(shù)據(jù)中的token
localStorage.setItem("eleToken", token)
將token存儲(chǔ)在瀏覽器本地
前端使用token實(shí)現(xiàn)路由守衛(wèi)
其實(shí)在后端代碼中寫(xiě)的unless就是路由守衛(wèi)的意思,不過(guò)前端應(yīng)該也要有這個(gè),不然不用登錄就可以訪(fǎng)問(wèn)到網(wǎng)站的內(nèi)容了,這顯然不合理
看看前端怎么寫(xiě)的,寫(xiě)在router.js中
import Vue from 'vue' import VueRouter from 'vue-router' import Index from './views/Index.vue' import Register from './views/Register.vue' import NotFound from './views/404.vue' import Login from './views/Login.vue' Vue.use(VueRouter) const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes: [ { path: '*', name: '/404', component: NotFound }, { path: '/', redirect: '/index' }, { path: '/register', name: 'register', component: Register }, { path: '/index', name: 'index', component: Index }, { path: '/login', name: 'login', component: Login }, ] }) // 路由守衛(wèi) router.beforeEach((to, from, next) => { const isLogin = localStorage.eleToken ? true: false if(to.path == '/login' || to.path == '/register'){ next() }else { isLogin ? next() : next('/login') } }) export default router
看路由守衛(wèi)后面的代碼就可以了
使用的是router中的beforeEach函數(shù)
使用的邏輯如下:
- 定義一個(gè)isLogin(布爾值),如果瀏覽器中l(wèi)ocalStorage中存有eleToken對(duì)象,則值為true,否則為false
- 確定哪些路由不需要攔截:to.path == '/login' || to.path == '/register'也就是登錄和注冊(cè)不需要攔截,直接放行,用next()
- 對(duì)于攔截的路由,判斷isLogin是否為true,是就說(shuō)明已經(jīng)登錄過(guò)了,有token,直接放行,如果為false,就跳轉(zhuǎn)到登錄的路由。
請(qǐng)求攔截和響應(yīng)攔截
還有一點(diǎn)沒(méi)有搞定,需要判斷當(dāng)前的token是不是過(guò)期了的,因?yàn)楹蠖藢?xiě)token的時(shí)候是給了個(gè)10小時(shí)的有效期,過(guò)期后,應(yīng)該重新登錄才對(duì)
這里我寫(xiě)在一個(gè)單獨(dú)的http.js文件中,先上代碼
import axios from "axios"; import { Message, Loading } from 'element-ui'; import router from "./router" let loading; function startLoading(){ loading = Loading.service({ lock: true, text: '數(shù)據(jù)加載中', background: 'rgba(0,0,0,0.7)' }) } function endLoading(){ loading.close(); } // 請(qǐng)求攔截 axios.interceptors.request.use(config => { startLoading(); if(localStorage.eleToken){ // 設(shè)置統(tǒng)一的請(qǐng)求頭 config.headers.Authorization = localStorage.eleToken } return config }, error => { return Promise.reject(error) }) //響應(yīng)攔截 axios.interceptors.response.use(response => { endLoading(); return response }, error => { // 錯(cuò)誤提醒 endLoading(); Message.error(error.response.data) // 獲取錯(cuò)誤狀態(tài)碼 const {status} = error.response if(status == 401){ Message.error("token失效,請(qǐng)重新登錄") localStorage.removeItem('eleToken') router.push('/login') } return Promise.reject(error) }) export default axios
看后面的請(qǐng)求攔截和響應(yīng)攔截就可以了
分兩步:
請(qǐng)求攔截,當(dāng)請(qǐng)求數(shù)據(jù)的時(shí)候,判斷l(xiāng)ocalStorage中是否存儲(chǔ)了eleToken,有的話(huà),就把它寫(xiě)到請(qǐng)求頭中去響應(yīng)攔截,當(dāng)token過(guò)期后,頁(yè)面會(huì)響應(yīng)一個(gè)401的錯(cuò)誤狀態(tài)碼,這里要做的事情就是要把這個(gè)過(guò)期的token清除,并跳轉(zhuǎn)到登錄頁(yè)面
注意,這里坑的一筆,坑了博主一個(gè)下午,我寫(xiě)的
頁(yè)面會(huì)響應(yīng)一個(gè)401的錯(cuò)誤狀態(tài)碼
對(duì)嗎,但是經(jīng)過(guò)測(cè)試,token過(guò)期后根本就沒(méi)有跳轉(zhuǎn)到登錄頁(yè)面啊,后來(lái)我打印了一下這個(gè)status,發(fā)現(xiàn)這個(gè)值等于0啊,坑爹呢不是嗎,所以響應(yīng)攔截這里正確的寫(xiě)法應(yīng)該是:
//響應(yīng)攔截 axios.interceptors.response.use(response => { endLoading(); return response }, error => { // 錯(cuò)誤提醒 endLoading(); Message.error(error.response.data) console.log(error.response) // 獲取錯(cuò)誤狀態(tài)碼 const {status} = error.response console.log(status) if(status === 0){ Message.error("token失效,請(qǐng)重新登錄") localStorage.removeItem('eleToken') // console.log(error) router.push('/login') } return Promise.reject(error) })
把狀態(tài)碼改過(guò)來(lái)后就正常跳轉(zhuǎn)了。
至此,前后端token的使用都已經(jīng)順暢了~~
總結(jié)
到此這篇關(guān)于vue項(xiàng)目中存儲(chǔ)與使用后端傳遞過(guò)來(lái)的token的文章就介紹到這了,更多相關(guān)vue存儲(chǔ)使用后端傳遞的token內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue.js?rules校驗(yàn)規(guī)則舉例詳解
Vue表單校驗(yàn)規(guī)則(rules)是一種用于驗(yàn)證表單數(shù)據(jù)的對(duì)象,它通常用于Vue.js框架中的表單組件中,可以在表單提交前進(jìn)行數(shù)據(jù)驗(yàn)證,這篇文章主要給大家介紹了關(guān)于Vue.js?rules校驗(yàn)規(guī)則的相關(guān)資料,需要的朋友可以參考下2024-02-02vue實(shí)現(xiàn)經(jīng)典選項(xiàng)卡功能
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)經(jīng)典選項(xiàng)卡功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03詳解三種方式解決vue中v-html元素中標(biāo)簽樣式
這篇文章主要介紹了三種方式解決vue中v-html元素中標(biāo)簽樣式,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-11-11ES6 Proxy實(shí)現(xiàn)Vue的變化檢測(cè)問(wèn)題
Vue3.0將采用ES6 Proxy的形式重新實(shí)現(xiàn)Vue的變化檢測(cè),在官方還沒(méi)給出新方法之前,我們先實(shí)現(xiàn)一個(gè)基于Proxy的變化檢測(cè)。感興趣的朋友跟隨小編一起看看吧2019-06-06Vue中為什么要引入render函數(shù)的實(shí)現(xiàn)
本文主要介紹了Vue中為什么要引入render函數(shù)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01淺談mint-ui loadmore組件注意的問(wèn)題
下面小編就為大家?guī)?lái)一篇淺談mint-ui loadmore組件注意的問(wèn)題。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11vue.extend,mixins和vue.component的區(qū)別及說(shuō)明
Vue.extend 創(chuàng)建Vue的子類(lèi),可視為組件構(gòu)造函數(shù),Vue.mixin 允許全局添加方法或?qū)傩?方便所有組件使用,Vue.component 是插件注冊(cè)方法,通過(guò)Vue.extend創(chuàng)建的組件實(shí)例可以注冊(cè)到Vue全局,使其在任何組件中可用2024-09-09