您好,登錄后才能下訂單哦!
為了實(shí)現(xiàn)前端校驗(yàn)用戶,后端需要在用戶登錄的時(shí)候記錄下該用戶的狀態(tài)并加密之后返回給前端。之后該用戶的所有請(qǐng)求都應(yīng)該附帶這個(gè)加密后的狀態(tài),后端取到這個(gè)狀態(tài)解密,并與之前保存的狀態(tài)對(duì)比,以此來判斷該用戶是否登錄或合法。
我這里使用了node簡單了寫了個(gè)本地的express服務(wù),來實(shí)現(xiàn)上述功能。完整的代碼直接貼出來:
// server.js const express = require('express'); const bodyParser = require('body-parser'); const jwt = require('jsonwebtoken'); const app = express(); // secret是后端加密的密鑰 const secret = 'rhwl'; app.use((req, res, next) => { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'GET,HEAD,OPTIONS,POST,PUT'); res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization'); if (req.method.toLowerCase() === 'options') { return res.end(); } next(); }); app.use(bodyParser.json()); app.post('/login', (req, res) => { const { username } = req.body; if (username === 'admin') { // 如果是合法用戶,使用jwt進(jìn)行加密生成token res.json({ code: 0, username: 'admin', token: jwt.sign({ username: 'admin' }, secret, { expiresIn: 20, }), }); } else { res.json({ code: 1, data: '用戶名不存在', }); } }); app.get('/validate', (req, res) => { const token = req.headers.authorization; // 在請(qǐng)求頭中附帶token信息 jwt.verify(token, secret, (err, decode) => { // 驗(yàn)證token是否合法 if (err) { return res.json({ code: 1, data: '當(dāng)前token無效', }); } // 如果驗(yàn)證合法,重新生成新的token,并返回信息 res.json({ username: decode.username, code: 0, token: jwt.sign({ username: 'admin' }, secret, { expiresIn: 20, }), }); }); }); app.listen(3000, ()=>{ console.log('服務(wù)器在3000端口運(yùn)行'); });
2.項(xiàng)目中axios封裝
然后我們在項(xiàng)目中封裝符合自己需求的ajax請(qǐng)求,現(xiàn)在通常都是基于axios庫。在自己封裝的ajax插件中,要在每次的請(qǐng)求頭中添加上token。代碼實(shí)現(xiàn):
// ajaxResquest.js import axios from 'axios'; class ajaxResquest { constructor(){ // 根據(jù)當(dāng)前模式自動(dòng)切換baseURL this.baseURL = process.env.NODE_ENV === 'development' ? 'http://localhost:3000' : '/'; this.timeout = 5000; // 設(shè)置請(qǐng)求超時(shí)為5s } request(config){ const instance = axios.create({ baseURL: this.baseURL, timeout: this.timeout, }); instance.interceptor.request.use((config) => { // 將保存在本地的token添加到每次請(qǐng)求的請(qǐng)求頭中 // 這樣就可以實(shí)現(xiàn)在請(qǐng)求時(shí)順帶附加用戶的校驗(yàn)信息的需求 config.headers.Authorization = localStorage.getItem('token'); return config; }, (err) => { return Promise.reject(err); }); instance.interceptor.response.use((req,res) => { return req.data; }, (err) => { Promise.reject(err); }); // 將使用request時(shí)候需要的參數(shù)也添加到instance中 return instance(config); } } export default new ajaxRequest();
然后統(tǒng)一管理項(xiàng)目api接口:
// api.js import ajax from 'ajaxResquest'; export const userLogin = (username) => ajax.request({url: '/login', method: 'POST', data: { username, }}); export const userValidate = () => ajax.request({url: '/validate'});
接下來我們在項(xiàng)目中具體實(shí)現(xiàn)用戶登陸和權(quán)限校驗(yàn)的需求。
3.vuex記錄用戶登錄
先將登陸組件配合vuex使用來觸發(fā)用戶登陸的行為,并且將用戶登錄之后的信息保存在vuex中,登陸組件的代碼:
// userLogin component <template> <div> <el-input v-model="username"></el-input> <el-button @click="login">登錄</el-button> </div> </template> <script> export default { data(){ return { username: '', } }, methods: { login(){ // 這里觸發(fā)vuex中的actions,在vuex中調(diào)用用戶登陸接口 // 從而將用戶登陸之后的狀態(tài)保存至vuex中 this.$store.dispatch('login', this.username).then((data) => { // 登陸成功之后,路由跳轉(zhuǎn)至用戶賬戶頁或者進(jìn)行你需要的操作 this.$router.push('/profile'); }); } } } </script>
接著是vuex的store.js
// store.js import Vue from 'vue'; import Vuex from 'vuex'; import {userLogin, userValidate} from 'api.js'; Vue.use(Vuex); export default Vuex.store({ state: { username: '', }, mutations: { setUsername(state, username){ state.username = username; } }, actions: { async login({commit}, username){ const res = await userLogin(username); if (res.code === 1) { // 登錄失敗 return Promise.reject(res); } // 登錄成功后將接口返回的token保存在本地 localStorage.setItem('token', res.token); // 將用戶名保存在vuex中 commit('setUsername', username); } } });
經(jīng)過上面的操作,我們將用戶登錄中調(diào)用登錄接口的操作通過vuex實(shí)現(xiàn),將成功登錄后的用戶名保存在vuex中,此時(shí)的token保存在瀏覽器本地。但是vuex中的數(shù)據(jù)并不是持久數(shù)據(jù),刷新之后保存的用戶名就會(huì)消失,接下來我們實(shí)現(xiàn)刷新頁面或者路由跳轉(zhuǎn)時(shí)進(jìn)行用戶校驗(yàn),如果驗(yàn)證通過則會(huì)生成新的token和username并保存。
4.vuex配合vue-router實(shí)現(xiàn)登錄校驗(yàn)
當(dāng)用戶刷新頁面時(shí),或者點(diǎn)擊其他頁面切換路由router時(shí),需要調(diào)用后端的validate接口,該接口通過驗(yàn)證已保存的token校驗(yàn)當(dāng)前用戶是否合法。我們在vuex的store.js中添加以下代碼:
export default Vuex.store({ state: { username: '', }, mutations: { setUsername(state, username){ state.username = username; } }, actions: { async login({commit}, username){ ... }, async validate({commit}) { // 調(diào)用userValidate時(shí),會(huì)將 const res = await userValidate(); if (res.code === 1) { // 此時(shí)用戶校驗(yàn)失敗 return Promise.reject(res); } // 如果校驗(yàn)成功,重新保存token和username localStorage.setItem('token', res.token); commit('setUsername', res.username); } } });
基本上我們通過上面的代碼就實(shí)現(xiàn)了用戶權(quán)限控制所需要的所有前提操作:
那么接下來就就是路由router刷新或改變的時(shí)候如何進(jìn)行權(quán)限控制了。
5.vue-router鉤子實(shí)現(xiàn)用戶權(quán)限控制
使用過vue-router的同學(xué)們都知道,路有也是有鉤子函數(shù)的,在官方文檔里面被稱為 導(dǎo)航守衛(wèi) 。導(dǎo)航守衛(wèi)允許我們可以精準(zhǔn)的在每個(gè)路由變化的時(shí)候進(jìn)行操作,我們就這里判斷用戶權(quán)限。在vue項(xiàng)目的的main.js中修改:
import Vue from 'vue'; import App from './App.vue'; import router from './router'; import store from './store'; import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; // 在這里使用路由的導(dǎo)航守衛(wèi)進(jìn)行權(quán)限控制 // 可以自定義不需要校驗(yàn)用戶的路由白名單 const whiteList = ['/']; router.beforeEach(async (to, from, next) => { // 要去的頁面是白名單,直接跳轉(zhuǎn) if (whiteList.includes(to.path)) { next(); } // 不是白名單,調(diào)用vuex中的validate行為 const flag = await store.dispatch('validate'); if (flag) { // 用戶校驗(yàn)通過,直接跳轉(zhuǎn) next(); } else { // 用戶校驗(yàn)失敗 next('/login'); // 跳轉(zhuǎn)至用戶登陸頁 // 順帶說一下,這里還可以在router中的meta屬性中添加isNeeded: true/false // 然后配合這個(gè)屬性更加精細(xì)的控制未通過用戶校驗(yàn)時(shí)的頁面是否允許跳轉(zhuǎn) } }); // vuex Vue.use(ElementUI); Vue.config.productionTip = false; new Vue({ router, store, render: h => h(App), }).$mount('#app');
總結(jié)
以上所述是小編給大家介紹的vue-router結(jié)合vuex實(shí)現(xiàn)用戶權(quán)限控制,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)億速云網(wǎng)站的支持!
如果你覺得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。