Vuex Vue-Router 登录鉴权 重定向返回

127 阅读1分钟

效果

动画.gif

功能

  1. 使用Vuex 控制登录
  2. 鉴权控制页码访问
  3. 重定向后返回

views

跳转到路由组件 Home: News: 需要鉴权 User: 需要鉴权 Login: 登录页 Loading: 鉴权等待页

解决如何登录

使用loginUser module 的状态 image.png

loginUser:有登录,退出登录,状态位置,和当前status

import * as userApi from "@/api/user.js";
export default {
  // 开启命名空间, 使用mutatio必须加上模块名
  namespaced: true,
  state: {
    loading: false,
    user: null,
  },
  mutations: {
    setLoading(state, payload) {
      state.loading = payload;
    },
    setUser(state, payload) {
      state.user = payload;
    },
  },
  actions: {
    async login(ctx, payload) {
      // ctx.commit("loginUser/setLoading", true);
      // 当前模块提交commit 可以省略模块名
      ctx.commit("setLoading", true);
      const resp = await userApi.login(payload.loginId, payload.loginPwd);
      ctx.commit("setUser", resp);
      ctx.commit("setLoading", false);
      return resp;
    },
    async whoAmI(ctx, payload) {
      ctx.commit("setLoading", true);
      const resp = await userApi.whoAmI();
      ctx.commit("setUser", resp);
      ctx.commit("setLoading", false);
    },
    async loginOut(ctx, payload) {
      ctx.commit("setLoading", true);
      await userApi.loginOut();
      ctx.commit("setUser", null);
      ctx.commit("setLoading", false);
    },
  },
  getters: {
    status(state) {
      if (state.loading) {
        return "loading";
      } else if (state.user) {
        return "login";
      } else {
        return "unLogin";
      }
    },
  },
};

鉴权

鉴权守卫示意图 image.png

如何判断哪些页面需要鉴权

在routes 给路由信息添加meta 元信息

import Home from "../views/Home.vue";
import Login from "../views/Login.vue";
import News from "../views/News.vue";
import User from "../views/User.vue";
import Loading from "../views/Loading.vue";

export default [
  { path: "/", component: Home },
  { path: "/login", component: Login },
  { path: "/loading", component: Loading },
  {
    path: "/news",
    component: News,
    meta: {
        // requireAuth===true 当前路由需要鉴权
      requireAuth: true,
    },
  },
  {
    path: "/user",
    component: User,
    meta: {
      requireAuth: true,
    },
  },
];

路由守卫进行鉴权

import VueRouter from "vue-router";
import routes from "./routes";
import Vue from "vue";
import store from "@/store";
Vue.use(VueRouter);
const router = new VueRouter({
  routes,
  mode: "history",
});
// router.beforeEach当发生路由跳转便会执行
// to : 目标路由, from : 源路由, nextTick : 路由钩子可接受一个路由对象
router.beforeEach((to, from, nextTick) => {
  if (to.meta.requireAuth) {
  // status:[login,unLogin,loading] 三种状态
    const status = store.getters["loginUser/status"];
    // 状态为loading, 跳转到鉴权等待页面, 将返回地址到添加路由查询参数
    if (status === "loading") {
      nextTick({
        path: "/loading",
        query: {
          returnUrl: to.fullPath,
        },
      });
    } else if (status === "login") {
      nextTick();
    } else {
      alert("您还没有登录,请登录!");
      nextTick({
        path: "/login",
        query: {
          returnUrl: to.fullPath,
        },
      });
    }
  } else {
    nextTick();
  }
});

export default router;

鉴权等待页的监控

loading.vue

<template>
    <div>
        <h1>loading</h1>
    </div>
</template>

<script>
export default {
    created() {
        // 返回一个注销监视的函数
        this.unWatch = this.$store.watch(
        // watch: 接受三个函数,1.为监听函数返回的值, 2. 将返回值给到函数2的形参,3. 是否立即监听
            () => this.$store.getters["loginUser/status"],
            (status) => {
                if (status !== "loading") {
               // status 变化后获取当前查询参数,否为默认/home,页面跳转, 由于会发生二查重定向添加catch
                    this.$router
                        .push(this.$route.query.returnUrl || "/home")
                        .catch(() => { })
                }
            },
            {
                immediate: true
            }
        )
    },
    destroyed() {
        this.unWatch()
    },
}
</script>

<style lang="scss" scoped></style>