Vue中用户状态管理

本篇博客主要介绍在Vue中如何进行用户登陆状态检查,即:

  1. 限制某些页面只有在登陆后才能访问;
  2. 如果用户的Cookie过期之后,跳转到登录页,让用户重新进行身份认证。

如果有更好的实现,欢迎各位评论区留言讨论。

1. 限制页面访问

某些页面既然登陆后才能访问,那么我们就可以在用户访问该受访问的页面的时候,检查其是否已经认证。这里主要是通过在vue-resource中添加请求拦截来来完成。
在这里插入图片描述
具体关键步骤:

  1. 在设置路由规则时,添加标记requiresAuth(只是一个标记,其他的名字也行);
  2. beforeEach方法中需要到达的下一个页面是否有标记requiresAuth,若是,则从浏览器中查找是否存在一个网站后端之前认证时保存的Cookie,如果没有,则代表没有认证或者认证已过期(因为浏览器会自动删除已经过期的Cookie),此时,重定位到登陆页面,并在登陆后返回当前页面。否则,不做任何处理,直接执行next()。

router/index.js

import Router from 'vue-router'
import Login from '@/components/Login.vue'
import Goods from '@/components/Goods.vue'
import Vue from 'vue'

// 注册路由器
Vue.use(Router)

// 定义路由规则
const router = new Router({
  routes: [{
    path: '/',
    name: 'goods',
    component: Goods
  },
  {
    path: '/login',
    name: 'login',
    component: Login
  },
  {
    path: '/goods',
    name: 'goods',
    component: Goods,
    meta: {
      requiresAuth: true// 标记需要登陆才能访问
    }
  }]
})

// 请求拦截器,过滤未登陆请求
router.beforeEach((to, from, next) => {
  if (to.matched.some(route => route.meta && route.meta.requiresAuth)) {
    // 根据Cookie判断是否认证成功,后端如果判断非法就将cookie设置过期
    var cookie = Vue.prototype.$cookies.get('miaosha_cookie')
    if (cookie == null) {
      // 这里会设置redirect参数
      console.log(to.fullPath)
      next({
        path: '/login',
        query: {redirect: to.fullPath}
      })
    } else {
      next()
    }
  } else {
    next()
  }
})

export default router

希望读者牢记,这里的限制只能限制正常用户的访问,更加安全的细节主要在后台完成。

2. 封装ajax请求

为什么要封装ajax请求,这里主要有两个原因:

  1. 项目需要每次请求时能携带Cookie到后台,以进行身份认证(Springboot后台每次检查Redis缓存中是否存在与当前Cookie对应的用户信息,Cookie和缓存信息的过期时间一致);
  2. 项目需要根据响应回来的自定义状态码,决定是否跳转到登陆页面。

下面介绍一下封装的时候的一些细节,需要注意的是,为了让请求携带Cookie,需要设置withCredentials为true。另外,在利用vue-router进行重定向时,设置登陆页面的地址,以及登陆完成后需要重定向的页面的地址。

export default {
  install(Vue, options) {
    // 封装GET请求方法
    Vue.prototype.queryGet = function (url, params, successCallback, errorCallback) {
        // 跨域携带cookie
        Vue.http.get(url, { withCredentials: true }).then((response) => {
          // 可以在这里判断ajax请求的code是否为95101、95102和95103,然后回到登录页
          let code = response.data.code;
          console.log(code)
          if (code !== '95101' && code !== '95102' && code !== '95103') {
             successCallback(response);
          } else {
            // 根据响应码,判断是否需要跳转到登录页
            console.log(params.redirect)
            this.$router.push({
              path: '/login',
              query: {redirect: params.redirect}
            })
          }
        }, (error) => {
          errorCallback(error);
        });
    }

    // 封装POST请求方法,直接访问相对路径即可
    Vue.prototype.ajaxPost = (url, params, successCallback, errorCallback) => {
      Vue.http.interceptors.push((request, next) => {
        // 跨域携带cookie
        request.withCredentials = true;
        next();
      });

      // 以Json格式提交数据
      Vue.http.post(url, params, {emulateJSON: true}).then((response) => {
        successCallback(response)
      }, (error) => {
        errorCallback(error)
      })
    }
  }
}

为了演示如何使用,这里给出一个例子。
在这里插入图片描述
如图所示,我们需要在打开页面时,从数据库中加载商品的信息。界面是使用element UI做的,这里就不做具体介绍了,主要关注一下,这里是在mounted生命周期函数中使用get请求的方式向springboot网站后台请求数据。

goods.vue

<template>
  <el-card>
    <div slot="header" class="clearfix">
      <span>商品列表</span>
    </div>
    <el-table
      :data="tableData"
      border
      style="width: 100%">
      <el-table-column
        prop="id"
        label="编号">
      </el-table-column>
      <el-table-column
        prop="name"
        label="名称">
      </el-table-column>
      <el-table-column
        label="图片"
        prop="imageUrl">
        <template slot-scope="scope">
          <img :src="scope.row.imageUrl" width="40" height="40" />
        </template>
      </el-table-column>
      <el-table-column
        prop="price"
        label="价格">
      </el-table-column>
      <el-table-column
        prop="stock"
        label="库存">
      </el-table-column>
      <el-table-column
        prop="note"
        label="备注">
      </el-table-column>
      <el-table-column
        label="操作">
        <template slot-scope="scope">
          <el-button @click="handleClick(scope.row)" type="text">详情</el-button>
        </template>
      </el-table-column>
    </el-table>
  </el-card>
</template>

<script>
  export default {
    data() {
      return {
        tableData: []
      }
    },
    mounted() {
      // 在页面加载完成后请求数据
      this.queryGet('/goods', {redirect: '/goods'}, response => {
        console.log(response.data.data)
        this.tableData = response.data.data
      }, e => {
        alert('ok');
      })
    }
  }
</script>

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/zyxhangiian123456789/article/details/107752396