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 请求

目的

  1. 每次请求时需要携带token到后台,进行身份认证;
  2. 项目需要根据响应回来的自定义状态码,决定是否跳转到登陆页面。

流程

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)

vue+ts下集----ts配置路由路由守卫数据交互-axios登录验证逻辑状态管理

Vue路由重定向、别名与导航守卫

vue项目权限管理

Vue-Router路由所有相关方法讲解(全),实战教学含登录拦截,万字长文,建议收藏