vue 跨平台授权登录的实现

191 阅读1分钟

要想实现项目A授权登录到项目B,必须满足以下几个条件:

①项目A 需要有 项目B 的token,将token作为url参数进行跳转;

②项目B 开放与 login 同级的路径,不做拦截;

③项目B 从url中获取token,写入浏览器 Cookies 后自动获取登陆信息,即可完成授权;

router/index.js
import Vue from "vue";
import Router from "vue-router";
/**
 * 不需要登录拦截的路由配置
 */
const loginIgnore = {
	names: ["404", "403"], // 根据路由名称匹配
	paths: ["/login", "/authorization"], // 根据路由fullPath匹配
	/**
	 * 判断路由是否包含在该配置中
	 * @param route vue-router 的 route 对象
	 * @returns {boolean}
	 */
	includes(route) {
		return this.names.includes(route.name) || this.paths.includes(route.path);
	}
};
/**
 * 初始化路由实例
 * @returns {VueRouter}
 */
function initRouter() {
	return new Router({
		mode: "history",
		routes: [{
			path: "/login",
			name: "login",
			meta: {
				title: "登录"
			},
			component: () => {
				return import("@/pages/login/LoginBlank");
			}
		},
		{
			path:"/start",
			name:"start",
			component: () => {
				return import("@/pages/StartView");
			}
		},
		{
			path: "/authorization",
			name: "authorization",
			meta: {
				title: "项目A授权登录项目B"
			},
			component: () => {
				return import("@/pages/authorization/Authorization");
			}
		},
		{
			path: "/404",
			name: "exp404",
			meta: {
				title: "404页面"
			},
			component: () => {
				return import("@/pages/exception/404");
			}
		},
		{
			path: "/500",
			name: "exp500",
			meta: {
				title: "500页面"
			},
			component: () => {
				return import("@/pages/exception/500");
			}
		},
		{
			path:"*",
			redirect: "/404"
		}]
	});
}

export {loginIgnore, initRouter};
router/guards.js
import { loginIgnore } from "@/router/index";

/**
 * 登录守卫
 * @param to
 * @param from
 * @param next
 * @param options
 */
const loginGuard = (to, from, next, options) => {
	const { message } = options;
	if (!loginIgnore.includes(to) && !checkAuthorization()) {
		message.warning("登录已失效,请重新登录");
		next({ path: "/login" });
	} else {
		//已登录,获取登录用户资料
		next();
	}
};

export default {
	beforeEach: [loginGuard]
};

/pages/authorization/Authorization

<template>
	<div class="authorize">
		<div class="authorize-top" style="background: #0074FE;">
			<img class="leftTopImg" src="https://gitee.com/lingxiu5858/assets/raw/master/img_authorize_rightBottom.png" alt="" />
			<span class="authorize-title">授权登录</span>
			<div class="authorize-content">
				<div class="logo">
					<div class="leftLogo">
						<img src="" alt="">
						<div class="title">项目A</div>
					</div>
					<div class="animation">
					</div>
					<div class="rightLogo">
						<img src="" alt="">
						<div class="title">项目B</div>
					</div>
				</div>
				<div class="container">
					<div class="authorize-text">
						<div class="tips">即将登录项目B</div>
					</div>
					<div class="authorize-operation">
						<div><a-button type="primary" @click="confirm" style="width: 364px; height: 40px; background: #0074FE;">确定</a-button></div>
						<div><a-button type="link"  @click="cancel" style="width: 364px; height: 40px; color: rgba(0,0,0,0.65);">返回</a-button></div>
					</div>
				</div>
			</div>
			<img class="rightBottomImg" src="https://gitee.com/lingxiu5858/assets/raw/master/img_authorize_rightBottom.png" alt="" />
		</div>
		<div class="authorize-bottom"></div>
	</div>
</template>

<script>
import Cookies from "js-cookie";
import {getCurrentUser} from "@/services/authService/login";
import {requestError, requestFail} from "@/utils/request";

export default {
	name: "Authorization",
	components:{ BkLottie },
	data() {
		return {
			routeQuery: this.$route.query,
			userInfo: {}
		};
	},
	created() {
		this.getCookies();
	},
	mounted() {
	},
	methods: {
		getCookies(){
			let { accessToken } = this.routeQuery;
			console.log("routeQuery", accessToken);
			Cookies.set("Authorization", encodeURIComponent(accessToken)); // token
			this.toGetCurrentUser();
		},
		// 获取当前登录用户信息
		toGetCurrentUser(){
			getCurrentUser().then((res)=>{
				let{data} = res;
				if(data && data.success){
					console.log("当前登录用户信息", data.result);
					this.userInfo = data.result;
				}else{
					requestFail(res, "");
				}
			}, requestError);
		},
		confirm(){
			location.replace("/");
		},
		cancel(){
			window.open("about:blank", "_self").close();
		}
	}
};
</script>
<style lang="less" scoped>
.authorize{
	margin: 0 auto;
	background: #FFFFFF;
	height: 100%;
	.authorize-top{
		width: 1920px;
		height: 464px;
		position: relative;
		border: 1px solid #979797;
		.leftTopImg{
			width: 249px;
			height: 204px;
		}
		.transparentLogo{
			position: absolute;
			top: 41px;
			width: 130px;
			height: 28px;
			margin-left: 61px;
		}
		.rightBottomImg{
			position: absolute;
			width: 631px;
			height: 371px;
			right: 0px;
			bottom: 0px;
		}
		.authorize-title{
			font-size: 32px;
			font-weight: 600;
			color: #FFFFFF;
			line-height: 45px;
			position: absolute;
			left: 45%;
			top: 25%;
		}
		.authorize-content{
			width: 586px;
			height: 620px;
			background: #FFFFFF;
			box-shadow: 0px 2px 20px 0px rgba(0,0,0,0.1);
			border-radius: 8px;
			position: absolute;
			left: 50%;
			top: 115%;
			transform: translate(-50%, -50%);
			.logo{
				margin: 104px 111px 0px 111px;
				display: flex;
				justify-content: center;
				align-items: center;
				.leftLogo, .rightLogo{
					img{
						width: 88px;
						height: 88px;
						margin-bottom: 8px;
					}
					.title{
						font-size: 14px;
						font-weight: 400;
						color: rgba(0,0,0,0.85);
						line-height: 20px;
						text-align: center;
					}
				}
				.animation{
					margin: 0px 60px;
				}
			}
			.container{
				margin-top: 122px;
				display: flex;
				justify-content: center;
				align-items: center;
				flex-direction: column;
				.authorize-text{
					display: flex;
					justify-content: center;
					align-items: center;
					flex-direction: column;
					margin-bottom: 41px;
					.tips{
						font-size: 14px;
						font-weight: 400;
						color: rgba(0,0,0,0.45);
						line-height: 20px;
					}
					.compName{
						font-size: 16px;
						font-weight: 600;
						color: rgba(0,0,0,0.85);
						line-height: 22px;
					}
				}
			}
		}
	}
	.authorize-bottom{
	}
}
</style>