爲了實現前端校驗用戶,後端須要在用戶登陸的時候記錄下該用戶的狀態並加密以後返回給前端。以後該用戶的全部請求都應該附帶這個加密後的狀態,後端取到這個狀態解密,並與以前保存的狀態對比,以此來判斷該用戶是否登陸或合法。javascript
我這裏使用了node簡單了寫了個本地的express服務,來實現上述功能。完整的代碼直接貼出來:css
// 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進行加密生成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; // 在請求頭中附帶token信息
jwt.verify(token, secret, (err, decode) => { // 驗證token是否合法
if (err) {
return res.json({
code: 1,
data: '當前token無效',
});
}
// 若是驗證合法,從新生成新的token,並返回信息
res.json({
username: decode.username,
code: 0,
token: jwt.sign({ username: 'admin' }, secret, {
expiresIn: 20,
}),
});
});
});
app.listen(3000, ()=>{
console.log('服務器在3000端口運行');
});
複製代碼
而後咱們在項目中封裝符合本身需求的ajax請求,如今一般都是基於axios庫。在本身封裝的ajax插件中,要在每次的請求頭中添加上token。代碼實現:html
// ajaxResquest.js
import axios from 'axios';
class ajaxResquest {
constructor(){
// 根據當前模式自動切換baseURL
this.baseURL = process.env.NODE_ENV === 'development' ? 'http://localhost:3000' : '/';
this.timeout = 5000; // 設置請求超時爲5s
}
request(config){
const instance = axios.create({
baseURL: this.baseURL,
timeout: this.timeout,
});
instance.interceptor.request.use((config) => {
// 將保存在本地的token添加到每次請求的請求頭中
// 這樣就能夠實如今請求時順帶附加用戶的校驗信息的需求
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時候須要的參數也添加到instance中
return instance(config);
}
}
export default new ajaxRequest();
複製代碼
而後統一管理項目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'});
複製代碼
接下來咱們在項目中具體實現用戶登錄和權限校驗的需求。vue
先將登錄組件配合vuex使用來觸發用戶登錄的行爲,而且將用戶登陸以後的信息保存在vuex中,登錄組件的代碼:java
// 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(){
// 這裏觸發vuex中的actions,在vuex中調用用戶登錄接口
// 從而將用戶登錄以後的狀態保存至vuex中
this.$store.dispatch('login', this.username).then((data) => {
// 登錄成功以後,路由跳轉至用戶帳戶頁或者進行你須要的操做
this.$router.push('/profile');
});
}
}
}
</script>
複製代碼
接着是vuex的store.jsnode
// 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);
}
}
});
複製代碼
通過上面的操做,咱們將用戶登陸中調用登陸接口的操做經過vuex實現,將成功登陸後的用戶名保存在vuex中,此時的token保存在瀏覽器本地。可是vuex中的數據並非持久數據,刷新以後保存的用戶名就會消失,接下來咱們實現刷新頁面或者路由跳轉時進行用戶校驗,若是驗證經過則會生成新的token和username並保存。ios
當用戶刷新頁面時,或者點擊其餘頁面切換路由router時,須要調用後端的validate接口,該接口經過驗證已保存的token校驗當前用戶是否合法。咱們在vuex的store.js中添加如下代碼:web
export default Vuex.store({
state: {
username: '',
},
mutations: {
setUsername(state, username){
state.username = username;
}
},
actions: {
async login({commit}, username){
...
},
async validate({commit}) {
// 調用userValidate時,會將
const res = await userValidate();
if (res.code === 1) { // 此時用戶校驗失敗
return Promise.reject(res);
}
// 若是校驗成功,從新保存token和username
localStorage.setItem('token', res.token);
commit('setUsername', res.username);
}
}
});
複製代碼
基本上咱們經過上面的代碼就實現了用戶權限控制所須要的全部前提操做:ajax
那麼接下來就就是路由router刷新或改變的時候如何進行權限控制了。
使用過vue-router的同窗們都知道,路有也是有鉤子函數的,在官方文檔裏面被稱爲導航守衛。導航守衛容許咱們能夠精準的在每一個路由變化的時候進行操做,咱們就這裏判斷用戶權限。在vue項目的的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';
// 在這裏使用路由的導航守衛進行權限控制
// 能夠自定義不須要校驗用戶的路由白名單
const whiteList = ['/'];
router.beforeEach(async (to, from, next) => {
// 要去的頁面是白名單,直接跳轉
if (whiteList.includes(to.path)) {
next();
}
// 不是白名單,調用vuex中的validate行爲
const flag = await store.dispatch('validate');
if (flag) { // 用戶校驗經過,直接跳轉
next();
} else { // 用戶校驗失敗
next('/login'); // 跳轉至用戶登錄頁
// 順帶說一下,這裏還能夠在router中的meta屬性中添加isNeeded: true/false
// 而後配合這個屬性更加精細的控制未經過用戶校驗時的頁面是否容許跳轉
}
});
// vuex
Vue.use(ElementUI);
Vue.config.productionTip = false;
new Vue({
router,
store,
render: h => h(App),
}).$mount('#app');
複製代碼
好了,以上就是由我整理的vuex配合路由router實現用戶權限控制,但願對你們有所幫助。 (此次分享的內容來源於某家的vue高級課程,由本人進行整理和分享~)
做者簡介: 晨光,人和將來大數據前端工程師。