Vue实现登录功能详解,前期配置(整合)(处理token,vuex配置,axios配置,router配置等)

奋斗吧
奋斗吧
擅长邻域:未填写

标签: Vue实现登录功能详解,前期配置(整合)(处理token,vuex配置,axios配置,router配置等) Vue.js博客 51CTO博客

2023-07-22 18:24:13 288浏览

Vue实现登录功能详解,前期配置(整合)(处理token,vuex配置,axios配置,router配置等),Vue实现登录功能详解,前期配置。后端收到请求,验证用户名和密码,验证成功,就给前端返回一个token;前端拿到token,将token存储到localStorage和vuex中,并跳转路由页面后端判断请求头中有无token,有token,就拿到token并验证token,验证成功就返回数据,验证失败

项目实现思路

1、第一次登录的时候,前端调后端的登陆接口,发送用户名和密码

2、后端收到请求,验证用户名和密码,验证成功,就给前端返回一个token

3、前端拿到token,将token存储到localStorage和vuex中,并跳转路由页面

4、前端每次跳转路由,就判断 localStroage 中有无 token ,没有就跳转到登录页面,有则跳转到对应路由页面

5、每次调后端接口,都要在请求头中加token

6、后端判断请求头中有无token,有token,就拿到token并验证token,验证成功就返回数据,验证失败(例如:token过期)就返回401,请求头中没有token也返回401

7、如果前端拿到状态码为401,就清除token信息并跳转到登录页面

项目主要文件

Vue实现登录功能详解,前期配置(整合)(处理token,vuex配置,axios配置,router配置等)_ios

Vue实现登录功能详解,前期配置(整合)(处理token,vuex配置,axios配置,router配置等)_ios_02

安装插件

npm install axios; // 安装axios
npm install vuex  // 安装vuex

配置vuex:token数据响应式+持久化

  • token一定要存在storage缓存中,否则刷新一下,store会重新被加载,token就没了;
  • 那存在store是不是多余了,这个也是为了数据统一管理吧,也是数据可视化,因为缓存中的数据代码中是看不见的。(为了代码更容易让别人理解所以加上vuex,不加也不影响做登录)

封装本地存储操作模块 src/utils/storage.js

/* 存储数据 */
export const setItem = (key, value) => {
  // 将数组、对象类型的数据转换为 JSON 格式字符串进行存储
  if (typeof value === "object") {
    value = JSON.stringify(value);
  }
  window.localStorage.setItem(key, value);
};

/* 获取数据 */
export const getItem = (key) => {
  const data = window.localStorage.getItem(key);
  try {
    return JSON.parse(data);
  } catch (err) {
    return data;
  }
};

/* 删除数据 */
export const removeItem = (key) => {
  window.localStorage.removeItem(key);
};

配置vuex处理token,创建src/store/index.js

import Vue from "vue";
import Vuex from "vuex";
// 加载storage模块:获取token,存储token
import { getItem, setItem } from "@/utils/storage";

Vue.use(Vuex);
// 用户登陆后的token值
const TOKEN_KEY = "X-Token";

export default new Vuex.Store({
  // 处理用户 Token,定义容器当中数据
  state: {
    // 用户的登录状态信息,存储当前登录用户信息(token等数据)
    // 1. user: null || JSON.parse(window.localStorage.getItem(TOKEN_KEY))
    user: getItem(TOKEN_KEY),
    LOADING: false, // vuex全局控制loading显示与隐藏
  },
  mutations: {
    setUser(state, data) {
      state.user = data;
      // 把数据备份到本地存储,防止vuex刷新丢失
      // window.localStorage.setItem(TOKEN_KEY, JSON.stringify(state.user))
      setItem(TOKEN_KEY, state.user);
    },
    showLoading(state) {
      state.LOADING = true;
    },
    hideLoading(state) {
      state.LOADING = false;
    },
  },
  actions: {},
  modules: {},
});

封装 axios 请求模块

二次封装axios请求(src\utils\request.js)

// 封装 axios 请求模块
import axios from "axios";
import store from "@/store";
import router from "@/router";

// axios.create 方法创建一个axios的实例
const request = axios.create({
  baseURL: "/localhost", // 接口的基准路径,监听拦截以/localhost开头的请求接口,并替换成target
});

// 请求拦截器:是否注入token
request.interceptors.request.use(
  function (config) {
    store.commit("showLoading");
    return config;
  },
  function (error) {
    store.commit("hideLoading");
    return Promise.reject(error);
  }
);

// store文件中vuex和localstorage对token进行处理之后响应拦截器中统一处理 token 过期
// 处理流程:在axios拦截器中加入token刷新逻辑;用户token过期时,向服务器请求新的 token;旧token替换为新token;然后继续用户当前的请求
// 响应拦截器
request.interceptors.response.use(
  function (response) {
    store.commit("hideLoading");
    return response;
  },
  async function (error) {
    store.commit("hideLoading");
    // console.dir(error);
    if (error.response && error.response.status === 400) {
      // 校验是否有token,没有的话请求失败,提示重新登陆
      const user = store.state.user;
      if (!user || !user.refresh_token) {
        router.push("/selectchongzhi");
        return;
      }
      // 如果有refresh_token,则请求获取新的 token
      try {
        const res = await axios({
          method: "PUT", // 对数据进行全部更新
          url: "/admin/waterMeter/login",
          headers: { "X-Token": localStorage.getItem("X-Token") },
        });

        // 如果获取成功,则把新的 token 更新到容器中
        console.log("刷新 token 成功", res);
        store.commit("setUser", {
          token: res.data.data.token, // 最新获取的可用 token
          refresh_token: user.refresh_token, // 还是原来的 refresh_token
        });
        return request(error.config);
      } catch (err) {
        // 如果获取失败跳转首页
        console.log("请求刷线 token 失败", err);
        router.push("/selectchongzhi");
      }
    }
    return Promise.reject(error);
  }
);

// http状态码拦截(可省略不写)
axios.defaults.validateStatus = (status) => {
  if (status === 403) {
    router.push({ name: "403" });
    return false;
  } else if (status === 500) {
    router.push({ name: "500" });
    return false;
  } else if (status === 503) {
    router.push({ name: "503" });
    return false;
  } else if (status === 401) {
    ElMessageBox.confirm(
      "登录状态已过期,您可以继续留在该页面,或者重新登录",
      "系统提示",
      {
        confirmButtonText: "重新登录",
        cancelButtonText: "取消",
        type: "warning",
      }
    ).then(() => {
      console.log("重新登录!");
    });
    return false;
  } else if (status === 404) {
    router.push({ name: "404-404" });
    return false;
  } else {
    return status >= 200 && status < 300;
  }
};

export default request;

在api/user.js里面发起接口请求

api文件的作用就是接口统一管理,最后把接口统一导出使用

// 存储接口封装,用户相关的请求模块
import request from "@/utils/request.js";

// -用户登录
export const login = (data) => {
  return request({
    method: "POST",
    url: "/admin/waterMeter/login",
    data,
  });
};

export const others = (params) => {
  return request({
    method: "GET",
    url: "/admin/information/others",
    params,
  });
};

export const listRecord = () => {
  return request({
    method: "GET",
    url: "/admin/record/listRecord",
    headers: { "X-Token": localStorage.getItem("X-Token") },
  });
};

组件页面中调用接口

登陆成功存储返回的token值

import { login } from '@/api/user'

async onSubmit (values) {
      let { mobile: vcPhone, password: vcLoginpassword } = values
      const { data } = await login({ vcPhone, vcLoginpassword, })
      // console.log(data);
      if (data.message == "跳转到首页") {
        this.$toast.success("登录成功");
        // 登录成功以后将后端返回的 token 相关数据存储到容器中
        this.$store.commit('setUser', data.data.token)
        this.$router.push({ name: "mychongzhi" });
      } else {
        this.$toast.fail('登录失败,请稍后重试')
      }
      // console.log("submit", values);
    },

在main.js中引入

import Vue from "vue";
import App from "./App.vue";
import router from "./router"; // 路由对象
import store from "./store"; // 管理用户token
import "vant/lib/index.css";
import "@/styles/common.less"; /*引入公共样式,放在Vant样式下否则会被Vant覆盖*/
import "amfe-flexible"; // 手机页面适配,动态设置 REM 基准值
import "./utils/time"; // 封装转化时间格式的函数
import axios from "axios";

Vue.config.productionTip = false;
Vue.prototype.$axios = axios;

new Vue({
  router,
  store,
  render: (h) => h(App),
}).$mount("#app");

好博客就要一起分享哦!分享海报

此处可发布评论

评论(0展开评论

暂无评论,快来写一下吧

展开评论

您可能感兴趣的博客

客服QQ 1913284695