为了账号安全,请及时绑定邮箱和手机立即绑定

Nuxt终篇:基于Vuex的权限验证探究

标签:
vuex

零、今天要完成橙色的部分

webp

image

为详情页增加权限验证

今天呢,咱们换一种玩儿法,就是将我们的详情页给增加一个权限,首页的数据大家都可以随便看,但是详情页却不能随便看,必须要登陆,那我们就需要在我们的详情页增加一个权限,

如果 token 存在,则发送请求验证,如果不存在,直接跳转到登录页,那我们首先要添加一个登录页

添加登录页,获取token

在 pages页面文件夹下,新建login 文件夹,然后添加 index.vue 登陆页面,

这一块逻辑和我们之前的很像,大家可以参考着做对比

webp

image

<template>
  <el-row type="flex" justify="center">
    <el-card v-if="isLogin"> 欢迎:admins <br>
      <br>
      <el-button type="primary" icon="el-icon-upload" @click="loginOut">退出登录</el-button>
    </el-card>
    <el-form v-else ref="loginForm" :model="user" :rules="rules" status-icon label-width="50px">
      <el-form-item label="账号" prop="name">
        <el-input v-model="user.name"></el-input>
      </el-form-item>
      <el-form-item label="密码" prop="pass">
        <el-input v-model="user.pass" type="password"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" icon="el-icon-upload" @click="login">登录</el-button>
      </el-form-item>
    </el-form>
  </el-row></template><script> import Vue from "vue";  export default {      methods: {        login: function() {          let that = this;
          that.$store.commit("saveToken", ""); this.$refs.loginForm.validate(valid => { if (valid) { //发送请求登陆,这里要注意下返回数据格式,如果有问题,参考 http.js 中的 response 设置
              Vue.http.get("Login/GetTokenNuxt?name="+that.user.name+"&pass="+that.user.name+"").then(res => { if (res.success) {                    console.log("登陆成功"); var token = res.token;
                    that.$store.commit("saveToken", token); this.$notify({                      type: "success",                      message: "欢迎你," + this.user.name + "!",                      duration: 3000 }); this.$router.replace("/");
                }
              }).catch(err => {                console.log("点赞失败", err);
              });
            } else { return false;
            }
          });
        },
        loginOut(){ this.isLogin=false; this.$store.commit("saveToken", "");
        }
      },
      data() { return {          isLogin:false,          user: {},          rules: {            name: [{ required: true, message: "用户名不能为空", trigger: "blur" }],            pass: [{ required: true, message: "密码不能为空", trigger: "blur" }]
          }
        };
      },
      created() {
      }
    } </script>

自定义 elementUI 插件

webp

image

提醒:这里我用到了 elementUI ,请安装

npm i element-ui -S

安装成功后,作为插件使用,如果你不是很了解,请访问官网《插 件》一章节,这里说的很清楚,我在之前的文件中也有提到。

在 plugins/server_site 文件夹下,新增 ElementUI.js 文件,作为我们的插件

import Vue from 'vue' import ElementUI from 'element-ui' Vue.use(ElementUI)

然后把这个 js 插件导入到 index.js 中,和 http.js一起注入到nuxt.config.js 中

//这个是 server_site 服务端插件全部import Vue from "vue";import http from "./http.js";import "./ElementUI.js";//导入 elementUI插件const install = function (VueClass, opts = {}) { // http method
    VueClass.http = http;
    VueClass.prototype.$http = http;
};
Vue.use(install);

因为我们是把服务端的插件都打包了 server_site 下的index中,所以我们以后不用每一个都注入到我们的配置文件 nuxt.config.js 中,只需要将 服务端插件 一个放进去即可,但是样式还是需要引用的

webp

image

在 strore 文件夹中,添加 index.js 文件,设置我们的store数据

webp

image

import Vue from "vue";import Vuex from "vuex";

Vue.use(Vuex); const store = () => new Vuex.Store({    state: {      isLogined: false,      token: "",//这里主要是用到了 token
 userInfo: {            name: "" },        loginBoxVisible: false },    mutations: { //保存 token 到 store和本地中
 saveToken(state, data) {
        state.token = data;        window.localStorage.setItem("Token", data);
      },
        changeLoginState (state, isLogined) {
            state.isLogined = isLogined;
        },
        changeLoginBoxVisible (state, visible) {
            state.loginBoxVisible = visible;
        },
        updateUserInfo (state, userInfo) {
            state.userInfo = userInfo;
        }
    },    actions: {
        initUser ({ state, commit }) { const user = JSON.parse(localStorage.getItem("userInfo")); if (user) {
                state.userInfo = user;
                commit("changeLoginState", true);
            }
        }
    }
});export default store;

在详情页中增加权限验证

大家一定还记得这个图片,这个是我们之前讲到的 nuxt 的执行流程图,这里说下 fetch()

webp

image

fetch 方法用于在渲染页面前填充应用的状态树(store)数据, 与 asyncData 方法类似,不同的是它不会设置组件的数据。

如果页面组件设置了 fetch 方法,它会在组件每次加载前被调用(在服务端或切换至目标路由之前)。

我们可以利用该方法,获取 状态树 中的 token 信息,并做处理,在昨天的基础上,我们只对 fetch() 方法,简单修改

<script> import Vue from "vue";  export default {    layout: "blog", async asyncData ({ params, error }) { // 获取文章详情
      let data = {}; try {
        data = await Vue.http.get(`blog/${params.id}`); return {          data: data
        };
      } catch (e) { //error({ statusCode: 404, message: "出错啦" });
 }
    }, //在这里进行判断 token
 fetch ({ store, redirect  }) { if (!(store.state.token&&store.state.token.length>=128)) { //跳转登录页
        return redirect('/login')
      }

    },
    data () { return {        comments: []
      };
    },
    head () { return {        title: `${this.data.btitle}`,        meta: [
          {            name: "description",            content: this.data.btitle
          }
        ]
      };
    }
  }; </script>

最后在 http.js 中,开启 http 拦截器

// http.interceptors.request.use((data, headers) => { // return data; // }); //http request 拦截器
 http.interceptors.request.use(    config => { //注意,首次服务端渲染的时候,还没有出现 DOM,所以找不到 windows 对象,这里用 try 处理掉了
      try { if (window.localStorage.Token&&window.localStorage.Token.length>=128) {//store.state.token 获取不到值
          config.headers.Authorization = window.localStorage.Token;
        }
      }catch (e) {
      } return config;
    },
    err => { return Promise.reject(err);
    }
  );

查看页面,体验效果

这里我们就已经限制了详情页,需要登陆才能查看,其实这一块逻辑我们可以单拿出来放到中间件 middleware 里来使用,效果会更好,这里举个栗子:路由鉴权

提醒: 因为我们用的是 store 判断的是否登陆,但是如果刷新页面,我们用的是 服务端渲染,所以 store 会被更新掉,也就是为空了,大家可以用两个办法处理
1、用 localStorage 来判断是否存在token;

2、每次服务端渲染,需要更新状态树 store 中的 token;



作者:SAYLINING
链接:https://www.jianshu.com/p/c53acbe52add


点击查看更多内容
2人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消