vue-router結(jié)合vuex實(shí)現(xiàn)用戶權(quán)限控制功能
為了實(shí)現(xiàn)前端校驗(yàn)用戶,后端需要在用戶登錄的時(shí)候記錄下該用戶的狀態(tài)并加密之后返回給前端。之后該用戶的所有請(qǐng)求都應(yīng)該附帶這個(gè)加密后的狀態(tài),后端取到這個(gè)狀態(tài)解密,并與之前保存的狀態(tài)對(duì)比,以此來(lái)判斷該用戶是否登錄或合法。
我這里使用了node簡(jiǎn)單了寫了個(gè)本地的express服務(wù),來(lái)實(shí)現(xiàn)上述功能。完整的代碼直接貼出來(lái):
// 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無(wú)效',
});
}
// 如果驗(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封裝
然后我們?cè)陧?xiàng)目中封裝符合自己需求的ajax請(qǐng)求,現(xiàn)在通常都是基于axios庫(kù)。在自己封裝的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'});
接下來(lái)我們?cè)陧?xiàng)目中具體實(shí)現(xiàn)用戶登陸和權(quán)限校驗(yàn)的需求。
3.vuex記錄用戶登錄
先將登陸組件配合vuex使用來(lái)觸發(fā)用戶登陸的行為,并且將用戶登錄之后的信息保存在vuex中,登陸組件的代碼:
// userLogin component
<template>
<div>
<el-input style="width:200px" 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)至用戶賬戶頁(yè)或者進(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)過(guò)上面的操作,我們將用戶登錄中調(diào)用登錄接口的操作通過(guò)vuex實(shí)現(xiàn),將成功登錄后的用戶名保存在vuex中,此時(shí)的token保存在瀏覽器本地。但是vuex中的數(shù)據(jù)并不是持久數(shù)據(jù),刷新之后保存的用戶名就會(huì)消失,接下來(lái)我們實(shí)現(xiàn)刷新頁(yè)面或者路由跳轉(zhuǎn)時(shí)進(jìn)行用戶校驗(yàn),如果驗(yàn)證通過(guò)則會(huì)生成新的token和username并保存。
4.vuex配合vue-router實(shí)現(xiàn)登錄校驗(yàn)
當(dāng)用戶刷新頁(yè)面時(shí),或者點(diǎn)擊其他頁(yè)面切換路由router時(shí),需要調(diào)用后端的validate接口,該接口通過(guò)驗(yàn)證已保存的token校驗(yàn)當(dāng)前用戶是否合法。我們?cè)趘uex的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);
}
}
});
基本上我們通過(guò)上面的代碼就實(shí)現(xiàn)了用戶權(quán)限控制所需要的所有前提操作:
- 用戶成功登陸在本地保存token
- 在自己封裝的ajax的請(qǐng)求頭部添加保存的token信息
- 后端服務(wù)提供對(duì)前端token的校驗(yàn)?zāi)芰?br />
那么接下來(lái)就就是路由router刷新或改變的時(shí)候如何進(jìn)行權(quán)限控制了。
5.vue-router鉤子實(shí)現(xiàn)用戶權(quán)限控制
使用過(guò)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) => {
// 要去的頁(yè)面是白名單,直接跳轉(zhuǎn)
if (whiteList.includes(to.path)) {
next();
}
// 不是白名單,調(diào)用vuex中的validate行為
const flag = await store.dispatch('validate');
if (flag) { // 用戶校驗(yàn)通過(guò),直接跳轉(zhuǎn)
next();
} else { // 用戶校驗(yàn)失敗
next('/login'); // 跳轉(zhuǎn)至用戶登陸頁(yè)
// 順帶說(shuō)一下,這里還可以在router中的meta屬性中添加isNeeded: true/false
// 然后配合這個(gè)屬性更加精細(xì)的控制未通過(guò)用戶校驗(yàn)時(shí)的頁(yè)面是否允許跳轉(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ì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺(jué)得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
- vue router+vuex實(shí)現(xiàn)首頁(yè)登錄驗(yàn)證判斷邏輯
- 基于vue,vue-router, vuex及addRoutes進(jìn)行權(quán)限控制問(wèn)題
- 基于Vue、Vuex、Vue-router實(shí)現(xiàn)的購(gòu)物商城(原生切換動(dòng)畫)效果
- vue-router+vuex addRoutes實(shí)現(xiàn)路由動(dòng)態(tài)加載及菜單動(dòng)態(tài)加載
- Vue-router 類似Vuex實(shí)現(xiàn)組件化開發(fā)的示例
- 詳解使用Vue Router導(dǎo)航鉤子與Vuex來(lái)實(shí)現(xiàn)后退狀態(tài)保存
- Vuex與Vue router的使用詳細(xì)講解
相關(guān)文章
如何使用Vuex+Vue.js構(gòu)建單頁(yè)應(yīng)用
這篇文章主要教大家如何使用Vuex+Vue.js構(gòu)建單頁(yè)應(yīng)用,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10
vue中el-tree結(jié)合el-switch實(shí)現(xiàn)開關(guān)狀態(tài)切換
本文主要介紹了vue中el-tree結(jié)合el-switch實(shí)現(xiàn)開關(guān)狀態(tài)切換,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-12-12
vue實(shí)現(xiàn)驗(yàn)證用戶名是否可用
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)驗(yàn)證用戶名是否可用,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-01-01
解決vue項(xiàng)目中遇到 Cannot find module ‘chalk‘ 報(bào)錯(cuò)的問(wèn)題
這篇文章主要介紹了解決vue項(xiàng)目中遇到 Cannot find module ‘chalk‘ 報(bào)錯(cuò)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11
一文帶你簡(jiǎn)單理解Vue的data為何只能是函數(shù)
如果data是一個(gè)函數(shù)的話,這樣每復(fù)用一次組件,就會(huì)返回一份新的data,下面這篇文章主要給大家介紹了關(guān)于簡(jiǎn)單理解Vue的data為啥只能是函數(shù)的相關(guān)資料,需要的朋友可以參考下2022-10-10
uniapp微信小程序axios庫(kù)的封裝及使用詳細(xì)教程
這篇文章主要給大家介紹了關(guān)于uniapp微信小程序axios庫(kù)的封裝及使用的相關(guān)資料,Axios是一個(gè)基于promise網(wǎng)絡(luò)請(qǐng)求庫(kù),作用于node.js和瀏覽器中axios-miniprogram-adapteraxios的小程序適配器,需要的朋友可以參考下2023-08-08

