登录判断,路由+API拦截+token刷新

简述

对于有些需要权限的页面,需要登录才能访问。登录判断,不同需求不同做法。最常见的一种就是重定向登录页。这种比较简单,可以使用路由守卫,对登录状态做判断,无登录则重定向到登录页。另一种相对于重定向页面的效果,用户体验感会更好,就是登录弹窗。自己在项目中也是使用了登录弹窗的方式。下面介绍不同需求不同的做法

路由拦截

通过路由守卫,在路由解析之前,对当前登录状态做判断。

  • beforeEach

     该方法有三个参数,分别:to、from、next
     1.	to:要跳转的路由对象(Object)
     2.	from:离开的路由对象(Object)
     3.	next:路由通过的方法(function)
    
/*判断to路由是否需要权限,是否需要登录
	一般需要登录才能访问的路由,可以在该路由的meta对象添加判断
	如:
	*/
	{
		name:"layout",
		components:()=>"./views/layout.vue",
		meta:{
			needLogin:true
		}
	}

router.beforeEach((to,from,next) => {
	if(to.meta.needLogin){
		//在这里可以进行一些登录提示
		next(false)
	}else{
		next()
	}
})

//以下处理情况
//1、没有登录,则跳转到之前的跳转前的页面

router.beforeEach((to,from,next) => {
	if(to.meta.needLogin){
		next(form.name)
	}else{
		next()
	}
})


/*2、没有登录,则弹出登录框
	*编写登录弹窗组卷login.vue
	*触发条件,本次例子的触发变量设置在store,showLogin:false(默认为false)
	*/
	router.beforeEach((to,from,next) => {
		if(to.meta.needLogin){
			store.showLogin = true
			next(false)
		}else{
			next()
		}
	})
  • 新窗口打开页面,出现白屏

对于需要打开新窗口页面,访问需要权限的页面,比较普遍的是调用

   const routeUrl = router.resolve({
     name: 'layout',
     params: { id: 123123}
   });
   window.open(routeUrl.href, '_blank');

对于这种情况,如果使用以上方法进行拦截,是会出现空白页。因为该操作是执行了window.open才对路由进行解析拦截,所以vue组件并未创建,就会出现空白页。那对于这种情况,该如何拦截呢
解决:不在局部方法里面调用window.open,而是在路由解析时beforeEach进行判断调用,

/*
*路由参数判断该页面是否需要新窗口弹出,open:true,
*设置一个变量控制open的值,因为重新打开一个新窗口,Vue对象重新创建,所有变量为变成初始值,
*可通过
*/
	{
		name:"layout",
		components:()=>"./views/layout.vue",
		meta:{
			needLogin:true,
			open:true
		}
	}

//路由跳转
 const goLayout = () => {
 	sessionStorage.setItem('open',true)//用于触发新页面跳转判断,如果没有一个全局变量作判断,容易进入si循环
  	router.push({
    	name: "layout",
   		params: { id: 123123}
  	})
 }
 
//路由拦截
	router.beforeEach((to,from,next) => {
		if(to.meta.needLogin){
			if("已登录"){
				if(sessionStorage.getItem('open')=='true'){
					sessionStorage.setItem('open',false)
					if(to.meta.open){
						window.open(to.href, "_blank");
						next(false)
					}else{
						next()
					}
			}else{
				next()
		}else{//没有登录
			store.showLogin = true
			next(false)
		}
	})

Api拦截+Token刷新

如果接口需要带token,可以在封装好的axios,进行登录判断,如果接口返回状态码为401,则弹出登录弹窗

因为平时开发vue项目占多,所以本次例子也是以vue为基础,使用axios。
axios封装,一般使用请求拦截器interceptors.request.use,响应拦截器interceptors.response.use

//创建axios
const service = axios.create({
  baseURL: import.meta.env.VITE_APP_API_URL,
  timeout: 20000,
});


/*
*因为主要对接口返回的状态进行逻辑判断,所以此处主要对响应拦截器的进行详细的逻辑操作,
*/

//http request 拦截器
service.interceptors.request.use(
	(config) => {
		if (config['needAuthenticated']) {//需要token校验的接口,接口添加needAuthenticated(boolean类型)
			config.headers = {
				"Content-Type": "application/json",
				"Authorization": token.value||localStorage.getItem('zhenti_au'),
			};
	}
)

//http request 拦截器
service.interceptors.request.use(
	(resp)=>{
		//接口请求成功逻辑操作,如状态码200
	},
	async (error) => {//请求失败逻辑操作,如状态码500,401,400
		/*
			该处只要简述状态码为401时的操作,因为接口返回status=401,代表无权限访问
			需要携带正确有效的userToken
			一般开发中,需要两个token值,一个请求权限接口需要携带的userToken,
			一个用来更新userToken的refreshToken。
			refreshToken的作用是提高用户体验感,减少登录次数。
			场景:当用户在已登录的状态操作权限请求的时候,userToken过期,会提示用户进行登录,并且跳转到登录页,
			这种用户体验感差,所以这时需要使用refreshToken去请求更新userToken重新发送请求。
			只有当userToken和refreshToken同时过期失效才提示用户进行登录
		*/
		const {user} = useStore()//获取store的用户user对象,user对象里面需要有个属性记录用户登录状态
		const status = error.response.status;//请求带权限的接口
		if(status === 401) {//userToken过期
			const refresh_token = user.refresh_token;
			if(refresh_token){//存在refresh_token
				try{
					const res = await refInstance({
						url: "",
						method: "POST",
						data:{
							refreshToken:refresh_token
						}
					});
					if(res.data.code){//请求更新userToken成功
						user.setToken(res.data.data.token)
						user.setRefreshToken(res.data.data.refresh_token)
						if(error.config.data){
							//这一步很关键,数据转化(具体看接口参数请求要求)
							error.config.data=JSON.parse(error.config.data)
						}
						return service(error.config);//重新发送请求
					}else{//请求更新userToken失败、则调到首页,清空用户数据,弹出登录弹窗
						router.push({ name: 'layout'});
						/*
							status = 1 用户未登录
							status = 0 用户已登录
							在登录弹窗组件监听store的用户变量status属性,为1则显示登录弹窗
						*/
						user.login.status = 1
						user.clean()//清空用户数据
					}
				}catch(err){//存在refresh_token,但是以过期,则调到首页,清空用户数据,弹出登录弹窗
					router.push({ name: 'layout'});
					user.login.status = 1
					user.clean()//清空用户数据
				}
			}else{//不存在refresh_token,如主动退出登录
				user.login.status = 1
			}
		}
)

总结

以上是简述开发当中常用的全局登录操作,如有更好的补充和方法,欢迎留言指点💖💖💖

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值