Vue实现登录功能详解,前期配置(整合)(处理token,vuex配置,axios配置,router配置等)
标签: Vue实现登录功能详解,前期配置(整合)(处理token,vuex配置,axios配置,router配置等) Vue.js博客 51CTO博客
2023-07-22 18:24:13 287浏览
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信息并跳转到登录页面
项目主要文件


安装插件
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)展开评论
暂无评论,快来写一下吧
展开评论

