diff --git a/apps/web-antd/src/router/guard.ts b/apps/web-antd/src/router/guard.ts index 588545278..c0749c703 100644 --- a/apps/web-antd/src/router/guard.ts +++ b/apps/web-antd/src/router/guard.ts @@ -50,22 +50,29 @@ function setupCommonGuard(router: Router) { */ function setupAccessGuard(router: Router) { // 一次性检查:hash 路由模式下,OAuth 回调的 code/state 在 URL query(?code=xxx)中, - // Vue Router 读不到,需要转存到 sessionStorage 供个人中心绑定页面使用 - const pendingBind = sessionStorage.getItem('socialBindAction'); - if (pendingBind === 'bind') { - const url = new URL(window.location.href); - const code = url.searchParams.get('code'); - const state = url.searchParams.get('state'); - if (code) { - sessionStorage.setItem('socialBindCode', code); - sessionStorage.setItem('socialBindState', state || ''); + // Vue Router 读不到,需要转存到 sessionStorage + const url = new URL(window.location.href); + const oauthCode = url.searchParams.get('code'); + if (oauthCode) { + const oauthState = url.searchParams.get('state') || ''; + const pendingBind = sessionStorage.getItem('socialBindAction'); + const pendingLogin = sessionStorage.getItem('socialLoginAction'); + if (pendingBind === 'bind') { + // 绑定回调:转存参数供个人中心使用 + sessionStorage.setItem('socialBindCode', oauthCode); + sessionStorage.setItem('socialBindState', oauthState); sessionStorage.removeItem('socialBindAction'); - // 清理 URL 中的 OAuth 参数 - url.searchParams.delete('code'); - url.searchParams.delete('state'); - url.searchParams.delete('appid'); - window.history.replaceState({}, '', url.toString()); + } else if (pendingLogin === 'login') { + // 登录回调:转存参数供 social-login 页面使用 + sessionStorage.setItem('socialLoginCode', oauthCode); + sessionStorage.setItem('socialLoginState', oauthState); + sessionStorage.removeItem('socialLoginAction'); } + // 清理 URL 中的 OAuth 参数 + url.searchParams.delete('code'); + url.searchParams.delete('state'); + url.searchParams.delete('appid'); + window.history.replaceState({}, '', url.toString()); } router.beforeEach(async (to, from) => { @@ -74,7 +81,15 @@ function setupAccessGuard(router: Router) { const authStore = useAuthStore(); const dictStore = useDictStore(); - // 社交绑定回调:检测到待处理的绑定参数,重定向到个人中心处理 + // 社交登录回调:重定向到 social-login 页面处理 + if ( + sessionStorage.getItem('socialLoginCode') && + to.path !== '/auth/social-login' + ) { + return '/auth/social-login'; + } + + // 社交绑定回调:重定向到个人中心处理 if ( sessionStorage.getItem('socialBindCode') && accessStore.accessToken && diff --git a/apps/web-antd/src/views/_core/authentication/login.vue b/apps/web-antd/src/views/_core/authentication/login.vue index e23292e61..d83aa3cee 100644 --- a/apps/web-antd/src/views/_core/authentication/login.vue +++ b/apps/web-antd/src/views/_core/authentication/login.vue @@ -97,15 +97,12 @@ async function handleThirdLogin(type: number) { return; } try { - // 计算 redirectUri - // tricky: type、redirect 需要先 encode 一次,否则钉钉回调会丢失。配合 social-login.vue#getUrlValue() 使用 - const redirectUri = `${ - location.origin - }/auth/social-login?${encodeURIComponent( - `type=${type}&redirect=${redirect || '/'}`, - )}`; - - // 进行跳转 + // hash 路由模式下,OAuth 回调的 code 在 URL query 中,Vue Router 读不到 + // 通过 sessionStorage 传递参数,redirect_uri 只用 origin + sessionStorage.setItem('socialLoginType', String(type)); + sessionStorage.setItem('socialLoginRedirect', (redirect as string) || '/'); + sessionStorage.setItem('socialLoginAction', 'login'); + const redirectUri = location.origin; window.location.href = await socialAuthRedirect(type, redirectUri); } catch (error) { console.error('第三方登录处理失败:', error); diff --git a/apps/web-antd/src/views/_core/authentication/social-login.vue b/apps/web-antd/src/views/_core/authentication/social-login.vue index 1052a9a18..fea7df5ea 100644 --- a/apps/web-antd/src/views/_core/authentication/social-login.vue +++ b/apps/web-antd/src/views/_core/authentication/social-login.vue @@ -70,13 +70,25 @@ async function fetchTenantList() { } /** 尝试登录:当账号已经绑定,socialLogin 会直接获得 token */ -const socialType = Number(getUrlValue('type')); -const redirect = getUrlValue('redirect'); -const socialCode = query?.code as string; -const socialState = query?.state as string; +// 优先从 sessionStorage 读取参数(hash 路由模式下 OAuth 回调参数在 URL query 中,Vue Router 读不到) +const socialType = Number( + sessionStorage.getItem('socialLoginType') || getUrlValue('type'), +); +const redirect = + sessionStorage.getItem('socialLoginRedirect') || getUrlValue('redirect'); +const socialCode = (sessionStorage.getItem('socialLoginCode') || + query?.code) as string; +const socialState = (sessionStorage.getItem('socialLoginState') || + query?.state) as string; +// 读取后清理 +sessionStorage.removeItem('socialLoginType'); +sessionStorage.removeItem('socialLoginRedirect'); +sessionStorage.removeItem('socialLoginCode'); +sessionStorage.removeItem('socialLoginState'); + async function tryLogin() { // 用于登录后,基于 redirect 的重定向 - if (redirect) { + if (redirect && redirect !== '/') { await router.replace({ query: { ...query, diff --git a/apps/web-antd/src/views/_core/profile/modules/user-social.vue b/apps/web-antd/src/views/_core/profile/modules/user-social.vue index 9f51a7c5f..ceed9bfc4 100644 --- a/apps/web-antd/src/views/_core/profile/modules/user-social.vue +++ b/apps/web-antd/src/views/_core/profile/modules/user-social.vue @@ -2,6 +2,7 @@ import type { SystemSocialUserApi } from '#/api/system/social/user'; import { computed, onMounted, ref } from 'vue'; + import { confirm } from '@vben/common-ui'; import { DICT_TYPE, SystemUserSocialTypeEnum } from '@vben/constants'; import { getDictLabel } from '@vben/hooks';