vue项目实战-----登录态管理(路由守卫+vuex+Axios)
Posted Coding With you.....
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue项目实战-----登录态管理(路由守卫+vuex+Axios)相关的知识,希望对你有一定的参考价值。
目的:保存用户登录状态,刷新页面时做到用户状态不变:一刷新就去localStorage中获取token与islogin对vuex中的信息进行更新
1.路由拦截/守卫+token+vuex管理
逻辑:
1.控制页面跳转
如果下一个页面需要登录,判断用户是否登录/是否有token:登录了且下一个不是登录界面就进入,是登录界面就去home;用户没有登录就去登录页------登录后得到token,将token存到store中以及本地。
如果下一个页面不需要登录,直接进入
2.刷新时保存状态
刷新时store会清零,这时就去缓存中拿token,然后去后台获取用户的信息,并将信息存储到store中
3.控制页面登录退出:登录与退出登录时更新状态中islogin
退出时要清空本地缓存哦
难点:
对于islogin,其值为true表示登录,false表示未登录,存放在localStorage里面,因为localStorage里面只能存字符串,所以存进去的时候需要localStorage.setItem(‘islogin’,JSON.stringify(islogin));将islogin变为String类型,取出来的时候需要将islogin转化为Boolean类型,就比如JSON.parse(localStorage.getItem(‘islogin’))这样。
或者可以直接将true/false保存为字符串进行存储
疑难解答
为什么本地存储了islogin或者token,还要在状态管理中进行管理呢?
islogin登录态的管理,vue不能实时监测localStorage的变化,需要实时监测islogin的变化来在页面显示登录还是已经登录,同时vuex中是只要刷新页面就会实时变化的,因此需要在状态管理中管理。
可以这样理解:本地化的存储只是为了控制刷新时的vuex更新,实际控制状态与检测的是vuex中的变量
最安全的就是在点击退出的时候清除本地缓存
islogin和token是否可以只需要一个,还是两个必须都有吗
严格意义上是需要两者都有的,主要是token;token从前后端的通信中进行传输携带,更加安全的验证
而且当状态为登录且用户信息也存在的时候才能算登录,因为token是一直存在的,登录状态不是。因此islogin为了判断用户是否登录,token可以进行前后端的校验
如何做到刷新页面时用户状态不变
页面刷新时,通过路由守卫判断,然后去本地存储中读取信息进行vuex的同步更新
流程
1.路由的配置path时;在需要守卫的path加上meta属性;用于表示下一个路由是否需要在登录后才能进入。
eg:
path: '/home',component: home,meta:requireAuth:true
2.全局守卫在main.js中设置 白名单中的直接访问,黑名单的需要登录
router.beforeEach((to, from, next) =>
if (to.meta.requireAuth) // 判断该路由是否需要登录权限
if(JSON.parse(localStorage.getItem('islogin'))) //判断本地是否存在token
if(to.path=='/login')
next(
path:'/home' //或者回到当前的路径,不进行跳转 from.path
)
elsenext();
else
next(
path:'/login'
)
else
next();
路由独享守卫
为防止,不经过某路由就直接 在地址栏输入本路由地址而跳转至 本路由,导致本路由获取不到前面路由的某些数据,所以给本路由加 路由独享守卫。
在每一个路由中加而不是在整体的路由上加beforeEnter及逻辑处理
3.store.js 用于保存与更新当前的状态信息
/store.js中
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store(
state:
//是否登录判断
islogin:''
,
mutations:
login:(state,n) =>
//传入登录状态islogin
let islogin = JSON.parse(n);
localStorage.setItem('islogin',JSON.stringify(islogin));
console.log(islogin);
state.islogin = islogin;
4.页面中触发登录态的地方 状态变更时更新vuex
//这里是登录
login()
let flag = true;
this.$store.commit('login',flag);
this.$router.push("/home");
console.log("登录成功");
//这里是退出登录
exit()
let flag = false;
this.$store.commit('login',flag);
this.$router.push("/login");
console.log("退出登录");
当前局限:只是限制了用户访问时路由页面的跳转
2.封装 Axios 请求
目的
- 每次请求时需要携带token到后台,进行身份认证;
- 项目需要根据响应回来的自定义状态码,决定是否跳转到登陆页面。
流程
1.axios
//axios 进行二次封装
//引入axios
import axios from "axios";
//在当前模块引入store
import store from '@/store';
//引入进度条 和 进度条样式 * 非必须
import nprogress from 'nprogress';
import 'nprogress/nprogress.css';
//1.利用axios对象的方法create,去创建一个axios实例
//2.这里requests就是axios,只不过稍微配置一下
const requests = axios.create(
//配置对象
//基础路径,发请求的时候,路径中会出现api
baseURL:"/api",
//请求超时的时间为5s
timeout:5000,
);
// 请求拦截器:在发请求之前,请求拦截器可以检测到,可以在请求发出去之前做一些事情
requests.interceptors.request.use((config)=>
if(store.state.detail.uuid_token)
config.headers.userTempId = store.state.detail.uuid_token;
//需要携带token带给服务器
if(store.state.user.token)
config.headers.token = store.state.user.token;
//进度条开始
nprogress.start();
return config;
);
//相应拦截器
requests.interceptors.response.use((res)=>
//成功回调
//进度条结束
nprogress.done();
return res.data;
,(error)=>
//失败回调
new Promise.reject(new Error('faile'));
);
export default requests;
2.vuex store.js
import reqGetCode,reqUserRegister,reqUserLogin,reqUserInfo,reqLogout from '@/api';
import setToken,getToken,removeToken from '@/utils/token'
//home模块“小”仓库
//state:数据仓库
const state =
code:'',
token:getToken(),
userInfo:
//actions:可以处理自己的业务逻辑,也可以异步
const actions =
//获取验证码
async getCode(commit,phone)
let result = await reqGetCode(phone);
// console.log(result)
if(result.code == 200 )
commit("GETCODE",result.data);
return "ok";
else
return Promise.reject(new Error('faile'));
,
//用户注册
async userRegister(commit,user)
let result = await reqUserRegister(user);
if(result.code == 200 )
return 'ok';
else
return Promise.reject(new Error(result.message));
,
//登陆业务
async userLogin(commit,data)
let result = await reqUserLogin(data);
if(result.code == 200)
commit('USERLOGIN',result.data.token);
//持久化存储token
setToken(result.data.token);
return 'ok';
else
return Promise.reject(new Error(result.message));
,
//获取用户信息
async getUserInfo(commit)
let result = await reqUserInfo();
if(result.code == 200)
commit('GETUSERINFO',result.data);
return 'ok';
else
return Promise.reject(new Error(result.message));
,
//退出登录
async userLogout(commit)
let result = await reqLogout();
if(result.code == 200)
commit('CLEAR');
return 'ok';
else
return Promise.reject(new Error(result.message));
const mutations =
GETCODE(state,code)
state.code = code;
,
USERLOGIN(state,token)
state.token = token;
,
GETUSERINFO(state,userInfo)
state.userInfo = userInfo;
,
//清楚本地用户数据
CLEAR(state)
state.token = '';
state.userInfo = ;
removeToken();
export default
state,
mutations,
actions,
getters,
3.token管理
//存token
export const setToken = (token) =>
localStorage.setItem('TOKEN',token);
//取token
export const getToken = () =>
return localStorage.getItem('TOKEN');
//清除token
export const removeToken = () =>
localStorage.removeItem('TOKEN');
4.路由配置界面 或者是main.js
//路由配置文件
import Vue from 'vue';
import VueRouter from 'vue-router';
import routes from './routes';
//使用VueRouter插件
Vue.use(VueRouter);
//引入store
import store from '@/store';
//先保存一份VueRouter
let originPush = VueRouter.prototype.push;
let originReplace = VueRouter.prototype.replace;
//重写push|replace
//第一个参数:往哪里跳(传递哪些参数)
/**
* call 和 apply 区别
* 相同点:都可以调用函数一次,都可以篡改函数的上下文一次
* 不同点:call与app传递参数用逗号隔开,apply方法执行,传递数组
*/
VueRouter.prototype.push = function(location,resolve,reject)
if(resolve && reject)
originPush.call(this,location,resolve,reject);
else
originPush.call(this,location,()=>,()=>);
VueRouter.prototype.replace = function(location,resolve,reject)
if(resolve && reject)
originReplace.call(this,location,resolve,reject);
else
originReplace.call(this,location,()=>,()=>);
//配置路由
let router = new VueRouter(
//路由配置
routes,
scrollBehavior (to,from,savedPosition)
return y:0
);
//理由全局守卫,前置守卫(跳转之前判断)
router.beforeEach(async(to,from,next) =>
// next();
//获取token
let token = store.state.user.token;
let name = store.state.user.userInfo.name;
if(token)
//用户已经登录
if(to.path == '/login')
next('/home');
else
if(name)
next();
else
try
await store.dispatch('getUserInfo');
next();
catch(error)
//清楚token
await store.dispatch('userLogout');
next('/login');
else
// 用户未登录
let toPath = to.path;
if(toPath.indexOf('/trade') != -1 ||
toPath.indexOf('/pay') != -1 ||
toPath.indexOf('/pausuccess') != -1 ||
toPath.indexOf('/center') != -1||
toPath.indexOf('/Search') != -1||
toPath.indexOf('/shopcart') != -1
)
next('/login');
else
next();
);
export default router;
以上是关于vue项目实战-----登录态管理(路由守卫+vuex+Axios)的主要内容,如果未能解决你的问题,请参考以下文章
Vue项目实战:电商后台管理系统(Vue+VueRouter+Axios+Element)
Vue项目实战:电商后台管理系统(Vue+VueRouter+Axios+Element)