vue-router结合vuex实现用户权限控制功能

为了实现前端校验用户,后端需要在用户登录的时候记录下该用户的状态并加密之后返回给前端。之后该用户的所有请求都应该附带这个加密后的状态,后端取到这个状态解密,并与之前保存的状态对比,以此来判断该用户是否登录或合法。

我这里使用了node简单了写了个本地的express服务,来实现上述功能。完整的代码直接贴出来:

// 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端口运行');
});

2.项目中axios封装

然后我们在项目中封装符合自己需求的ajax请求,现在通常都是基于axios库。在自己封装的ajax插件中,要在每次的请求头中添加上token。代码实现:

// 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'});

接下来我们在项目中具体实现用户登陆和权限校验的需求。

3.vuex记录用户登录

先将登陆组件配合vuex使用来触发用户登陆的行为,并且将用户登录之后的信息保存在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(){
      // 这里触发vuex中的actions,在vuex中调用用户登陆接口
      // 从而将用户登陆之后的状态保存至vuex中
      this.$store.dispatch('login', this.username).then((data) => {
        // 登陆成功之后,路由跳转至用户账户页或者进行你需要的操作
        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);
    }
  }
});

经过上面的操作,我们将用户登录中调用登录接口的操作通过vuex实现,将成功登录后的用户名保存在vuex中,此时的token保存在浏览器本地。但是vuex中的数据并不是持久数据,刷新之后保存的用户名就会消失,接下来我们实现刷新页面或者路由跳转时进行用户校验,如果验证通过则会生成新的token和username并保存。

4.vuex配合vue-router实现登录校验

当用户刷新页面时,或者点击其他页面切换路由router时,需要调用后端的validate接口,该接口通过验证已保存的token校验当前用户是否合法。我们在vuex的store.js中添加以下代码:

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);
    }
  }
});

基本上我们通过上面的代码就实现了用户权限控制所需要的所有前提操作:

  • 用户成功登陆在本地保存token
  • 在自己封装的ajax的请求头部添加保存的token信息
  • 后端服务提供对前端token的校验能力

那么接下来就就是路由router刷新或改变的时候如何进行权限控制了。

5.vue-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');

总结

以上所述是小编给大家介绍的vue-router结合vuex实现用户权限控制,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

(0)

相关推荐

  • 使用vue-router在Vue页面之间传递数据的方法

    前言 几周前,我写了关于 Vue 路由的使用和在 Vue 页面导航的文章.这是在应用程序中探索的一个基本例子. 通常,在将导航构建到应用程序中时,您会发现需要将数据从一个页面传递到另一个页面.(不通顺)例如,您遵循 master-detail 模式,其中您有一个数据列表,通过更深入地挖掘可以获得关于列表中特定项的更多信息. 我们将学习如何使用路由和 URL参数以及查询参数在 Vue 页面之间传递数据. 如果你还没有读过我之前的教程或者不熟悉 vue-router 库,我建议你温习一下. 利用 U

  • vue-router的钩子函数用法实例分析

    本文实例讲述了vue-router的钩子函数用法.分享给大家供大家参考,具体如下: vue路由钩子大致可以分为三类: 1.全局钩子 主要包括beforeEach和aftrEach, beforeEach函数有三个参数: to:router即将进入的路由对象 from:当前导航即将离开的路由 next:Function,进行管道中的一个钩子,如果执行完了,则导航的状态就是 confirmed (确认的):否则为false,终止导航. afterEach函数不用传next()函数 这类钩子主要作用于

  • 使用vue-router切换页面时实现设置过渡动画

    背景 今天在编写页面时,看到页面没有任何效果就只是直入直出,完全没有一点逼格,所以想要实现类似于原生app的那种切换页面时的特效,遂开始google,发现网上各种方案都是各有优缺点,于是整理了自认为优雅的方案并记录下来. 实现难点 如何判断切换路由时是前进还是后退 每次切换时向左向右切换动画如何实现 解决方案 我们需要给各个页面定义层级,在切换路由时判断用户是进入哪一层页面,如果用户进入更高层级那么做前进动画,如果用户退到低层级那么做后退动画. router/index.js import Vu

  • 浅谈vue-router路由切换 组件重用挖下的坑

    问题描述:vue-router导航切换 时,如果两个路由都渲染同个组件,组件会重(chong)用,组件的生命周期钩子不会再被调用,使得组件的一些数据无法根据 path的改变得到更新 翻车现场再现: 这是我的/router/index.js 的内容节选 export default new Router({ routes: [ { path: '/main', component: Main }, { path: '/get', component: Main } ] }) 这是我的 Main.v

  • 详解vue-router 动态路由下子页面多页共活的解决方案

    我们都知道 vue-router 的动态路由匹配对组件是原地复用的策略,需要我们在组件中根据不同的 $route 参数展示不同的数据,这在大部分情景下是很高效的做法,但这无疑增加了组件的复杂度,而且不同参数间切换因为是同组件复用,切换效果不加修饰的话会显得很生硬,这里放一张图片感受一下. 如果我们希望能够每个动态参数都能渲染出一个组件而不是去复用怎么办呢? 我这里提供一个简便的方案 通常动态路由我们都是用来处理详情页 const router = new VueRouter({ routes:

  • vue-router两种模式区别及使用注意事项详解

    本文实例讲述了vue-router两种模式区别及使用注意事项.分享给大家供大家参考,具体如下: Vue Router 是Vue官方的路由管理器.它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌.vue-router 默认 hash 模式,还有一种是history模式. hash模式 hash模式的工作原理是hashchange事件,可以在window监听hash的变化.我们在url后面随便添加一个#xx触发这个事件. window.onhashchange = function(

  • 浅析vue-router中params和query的区别

    1.引入方式不同 query要用path来引入 this.$router.push({ path: 'test', query: { type: 2, detail: '哈哈' } }) params要用name来引入 this.$router.push({ name: 'test', query: { type: 2, detail: '哈哈' } }) 2.url不同 query在url中显示参数 http://localhost:8080/detail?type=0&detail=哈哈 p

  • vue-router二级导航切换路由及高亮显示的实现方法

    这里以网易云音乐作为示例,效果图: 我们先一层一层写导航 先设计第一层 1.设计导航页面样式 第一个导航页面为Discover Discover.vue: <!-- --> <template> <div> 发现 </div> </template> <script> export default { name: "discover", data() { return { }; } }; </script&g

  • 移动端底部导航固定配合vue-router实现组件切换功能

    在我们平时练习或者实际项目中也好,我们常常遇到这么一个需求:移动端中的导航并不是在顶部也不是在底部,而是在最底部且是固定的,当我们点击该导航项时会切换到对应的组件. 相信对于很多朋友而言,这是一个很简单的需求,而且市面上有很多开源的组件库就可以实现,像比如说:cube-ui等!那么对于一个要是还在练习以及对第三方组件库不是很了解的朋友不妨看看我这篇,相信会对你有所收获的! 首先,在实现这个需求之前,我们先分析或者回想下和自己做过的demo中哪个类似,相信很多朋友立马就会想起来---tab栏切换,

  • vue-router跳转时打开新页面的两种方法

    最近还是在痛苦的挣扎中 挣扎吧 记录一下在vue项目中如何实现跳转到一个新页面(一个比较简单又比较基础的问题了),有两个方法: 1.<vue-link>标签实现新窗口打开 官方文档中说 v-link 指令被 <router-link> 组件指令替代,且 <router-link> 不支持 target="_blank" 属性,如果需要打开一个新窗口必须要用<a>标签,但事实上vue2版本的 <router-link> 是支持

  • vue-router 中 meta的用法详解

    如果我想做下面这个功能: 路由 代码: 用这个获取 以上这篇vue-router 中 meta的用法详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • 解决vue-router 二级导航默认选中某一选项的问题

    现在有一个需求是这样的: 这个需求很正常吧! 二级导航条,不是二级路由的(如果是二级路由是用linkActiveClass来做,我之前文章说过),是单纯获取数据的按钮,当这个页面出现时,默认选中第一项. 首先: 上面的判断的意思是:如果你点击某一个选项把这个index传过去,activeName等于那一个传过来的index(index是遍历出来的数据如:1,2,3,4,5),就显示该个active或者index==pid,pid默认为0,所以index==0,就是默认第一个选项被选中. 但是当我

  • vue学习之Vue-Router用法实例分析

    本文实例讲述了vue学习之Vue-Router用法.分享给大家供大家参考,具体如下: Vue-router就像一个路由器,将组件(components)映射到路由(routes)后,通过点击<router-link>它可以在<router-view>中将相应的组件渲染出来. 1.使用vue-router的步骤 //1.创建路由组件 const Link1={template:'#link1'}; const Link2={template:'#link2'}; const Link

  • vue-router之实现导航切换过渡动画效果

    过渡动效 提供了transition的封装组件,添加过渡动画,通过添加或删除css类名来实现. 过渡的css类名: v-enter 进入过渡的开始状态 v-enter-active 进入活动状态 v-enter-to 进入的结束状态 v-leave 离开过渡的开始状态 v-leave-active 离开活动状态 v-leave-to 离开结束状态 过渡模式: in-out 先进后出 out-in 先出后进 用法: 做一个淡隐淡出效果 把想要运动的元素放到<transition></tra

  • vue-router路由模式详解(小结)

    一.路由模式解析 要讲vue-router的路由模式,首先要了解的一点就是路由是由多个URL组成的,使用不同的URL可以相应的导航到不同的位置. 如果有进行过服务器开发或者对http协议有所了解就会知道,浏览器中对页面的访问是无状态的,所以我们在切换不同的页面时都会重新进行请求.而实际使用vue和vue-router开发就会明白,在切换页面时是没有重新进行请求的,使用起来就好像页面是有状态的,这是什么原因呢. 这其实是借助了浏览器的History API来实现的,这样可以使得页面跳转而不刷新,页

  • 详解新手使用vue-router传参时注意事项

    1. 使用name和params组合传参 this.$router.push({name: 'details', params: {'id': 233}}) 路由配置 import Vue from 'vue' import Router from 'vue-router' Vue.use(Router) export default new Router({ mode: 'history', routes: [ { path: '/details', name: 'details', comp

  • vue实现权限控制路由(vue-router 动态添加路由)

    用户登录后返回权限菜单,前端根据权限菜单动态添加路由,然后再动态生成菜单栏. 思路如下: 一.定义初始化默认路由. 二.动态配置路由,这里是把所有组件中相应的路由配置成一个个的对象,根据后台返回的菜单tree一个个去匹配. 三.通过匹配,把匹配好的路由数据addRoutes到路由中. 四.为了防止刷新页面后路由数据被清空,这里用判断是否登录的方式,再次加载动态路由. 具体代码如下: router.js import Vue from 'vue' import {router} from './i

  • Vue路由管理器Vue-router的使用方法详解

    router-link <router-link> 组件支持用户在具有路由功能的应用中点击导航. 通过 to 属性指定目标地址,默认渲染成带有正确链接的 <a> 标签,可以通过配置 tag 属性生成别的标签.另外,当目标路由成功激活时,链接元素自动设置一个表示激活的 CSS 类名 <router-link> 比起写死的 <a href="..." rel="external nofollow" > 会好一些.无论是 H

随机推荐