美文网首页H5前端技术分享Vue.jsVue.js专区
基于Vue+VueRouter+Vuex+Axios的用户登录态

基于Vue+VueRouter+Vuex+Axios的用户登录态

作者: 胡哥有话说 | 来源:发表于2019-06-19 20:22 被阅读19次

    前言

    前后端分离开发、独立部署,为前端的开发人员提供了极大的便利,同时也带来了新的挑战。

    前后端分离带来的问题

    基于前端分离带来的问题
    1. 在路由级,模块之间的切换、跳转需要前端进行独立的维护
    2. 在接口级,前后端数据交互由接口进行连接(异步)

    这是重点:前端需要根据用户的登录态或角色身份进行权限控制拦截,以展示对应的功能模块或者是展示对应的数据。

    接下来胡哥就给小伙伴分享下在实际项目中的基于Vue+VueRouter+Vuex+Axios的用户登录态路由级和接口级拦截的原理与实现。

    路由级拦截

    1. 问题思考

      • 怎么拦截

        // 借助于VueRouter的钩子函数beforeEach,判断是否有权限进入,执行next()或next(false)
        router.beforeEach((to, from ,next) => {
          // next() 通过,允许进入
          // next(false) 禁止,不允许进入该模块
        })
        
      • 拦谁

        // 在VueRouter的路由配置项中,增加meta属性,设置是否需要权限验证的标记
        // 用户中心路由
        {
            path: 'user',
            name: 'User',
            Component: User,
            Meta: {
                // 需要权限验证
                requireAuth: true
            }
        }
        
    2. 实现方案

      • 安装vue-router

        npm i vue-router -D
        
      • 定义路由以及路由设置权限标志

        import Vue from 'vue'
        import VueRouter from 'vue-router'
        
        Vue.use(VueRouter)
        
        const router = new VueRouter({
            // 路由规则
            routes: [
                {
                    path: '/',
                    name: 'Home',
                    // 引入的模块默认是已经引入并定义了,这里不多描述
                    component: Home,
                    children: [
                        {
                            path: 'index',
                            name: 'Index',
                            component: Index,
                            // 定义元信息
                            meta: {
                                // 权限验证标记 false 不进行校验拦截
                                requireAuth: false
                            }
                        },
                        {
                            path: 'user',
                            name: 'User',
                            component: User,
                            meta: {
                                // 权限验证标记 true 进行校验拦截
                                requireAuth: true
                            }
                        },
                        {
                            path: 'login',
                            name: 'Login',
                            component: Login,
                            meta: {
                                // 权限验证标记 false 不进行校验拦截
                                requireAuth: false
                            }
                        }
                    ]
                }
            ]
        })
        
      • 权限拦截判定

      以用户登录态作为标志,进行登录验证

       ``` javascript
       const router = new VueRouter({
           routes: [
               // ...
           ]
       })      
       // 权限拦截-beforeEach路由钩子函数
       router.beforeEach (to, from, next) {
           // to 目的路由对象 from 来源路由对象
           if (to.match.some(rocode => recode.meta.requireAuth)) {
               /**
               * 登录状态-可使用aixos进行请求,拉取服务器数据,获取用户登录状态
               * 强烈建议在本地使用localStorage或sessionStorage和vuex共同管理用户登录态,避免每次进入时都拉取服务器端接口以验证用户是否登录,额外消耗对服务器的请求,提升用户体验
               * 如果已登录,则更新store中存储的loginName -- 详细查看下面的store配置
               * 未登录,则直接跳转走
               */ 
               let isLogin = 已登录 ? true : false
               // 执行拦截判定
               if (!isLogin) {
                   // 跳转到登录模块
                   // 处理方式一:借助next()方法
                   next({
                       name: 'Login',
                       replace: 'true',
                       // redirectUrl 用于标记登录后回跳的地址
                       redirectUrl: to.fullPath
                   })
                   
                   // 处理方式二:使用window.loaction.href方式,需要执行next(false)配合使用
                   window.location.href = '指定的登录地址?redirectUrl=' + to.fullPath
                   next(false)
               } else {
                   // 已登录,直接进入
                   next()
               }    
           } else {
               // 不执行拦截,直接进入该路由
               next()
           }
       }   
       ```
      

    接口级拦截

    1. 问题思考

      • 怎么拦截

        借助axios的拦截器:
        interceptors.request.use 请求拦截器
        interceptors.response.use 响应拦截器
        
      • 拦谁

        设置特定的接口地址白名单,用于是否进行用户登录态权限判定

        不是所有的接口都要进行拦截的,比如:
            1. 发送和获取登录信息的接口
            2. 发送注册信息的接口
            3. 其他不需要用户态的接口
        
    2. 实现方案

      • 安装axios

        npm i axios -D
        
      • 引入axios,添加拦截器

        import axios from 'axios'
        import router from '@/router'
        // 具体数据仓库对象store配置请往下看
        import store from '@/store'
        const $http = axios.create({
            // 基本配置项
        })
        
        // 定义接口地址白名单
        const allowUrls = [
            '/getUserInfo',
            '/addUserInfo'
        ]
        
        // 请求拦截器 -- 发送请求前,判断是否存在登录信息
        $http.interceptors.resquest.use((config) => {
            // config.url 是请求的URL地址
            if (allowUrls.includes(config.url)) {
                // 判断是否登录 --- 本地信息以及vuex的store信息进行判定
                let isLogin = locationStorage.getItem('isLogin')
                if (!isLogin || !store.state.loginName) {
                    // 携带当路由地址,跳转登录
                    // router.currentRoute.fullPath
                } else {
                    return config
                }
            } else {
                // 不需要判定则直接返回config配置
                return config
            }
        })
        
        // 响应拦截器
        $http.interceptors.response.use((res) => {
            // 判断是否需要验证权限
            if (allowUrls.includes(res.config.url)) {
                // 判断是否登录 --- 本地信息、vuex的store信息以及后端服务器响应回来的是否登录的标记
                let isLogin = locationStorage.getItem('isLogin')
                // 约定 code 10011 表示未登录
                if (!isLogin || !store.state.loginName || res.data.code === 10011) {
                    // 携带当路由地址,跳转登录
                    // router.currentRoute.fullPath
                } else {
                    return config
                }
            } else {
                return res
            }
        })
        

    数据仓库sotre

    1. 下载安装vuex

      npm i vuex -D
      
    2. 配置相关项

      import Vue from 'vue'
      import Vuex from 'vuex'
      
      Vue.use(Vuex)
      
      const store =  new Vuex.Store({
          state: {
              // 用户登录后,获取昵称
              loginName: ''
          },
          mutations: {
              updateLoginInfo (state, loginName) {
                  state.loginName = loginName
              }       
          }
      })
      
      

    后记

    以上就是胡哥今天给大家分享的内容,喜欢的小伙伴记得收藏、转发、点击在看呦…

    胡哥有话说,一个有技术,有情怀的胡哥!京东开放平台首席前端攻城狮。与你一起聊聊大前端,分享前端系统架构,框架实现原理,最新最高效的技术实践!

    长按扫码关注,更帅更漂亮呦!

    胡哥有话说

    相关文章

      网友评论

        本文标题:基于Vue+VueRouter+Vuex+Axios的用户登录态

        本文链接:https://www.haomeiwen.com/subject/jmckqctx.html