mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-09-24 16:05:44 +08:00
Merge pull request #3560 from StarryKira/feat/issue-3557-oauth-email
feat: fix OAuth email completion flow
This commit is contained in:
@@ -20,11 +20,24 @@ describe('API Client', () => {
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks()
|
||||
vi.unstubAllEnvs()
|
||||
})
|
||||
|
||||
// --- 请求拦截器 ---
|
||||
|
||||
describe('请求拦截器', () => {
|
||||
it('规范化相对 API base,避免在回调页拼出相对 v1 路径', async () => {
|
||||
vi.resetModules()
|
||||
vi.stubEnv('VITE_API_BASE_URL', 'api/v1')
|
||||
|
||||
const mod = await import('@/api/client')
|
||||
|
||||
expect(mod.apiClient.defaults.baseURL).toBe('/api/v1')
|
||||
expect(mod.buildApiUrl('/auth/oauth/github/callback?code=abc')).toBe(
|
||||
'/api/v1/auth/oauth/github/callback?code=abc'
|
||||
)
|
||||
})
|
||||
|
||||
it('自动附加 Authorization 头', async () => {
|
||||
localStorage.setItem('auth_token', 'my-jwt-token')
|
||||
|
||||
|
||||
+15
-5
@@ -1,20 +1,30 @@
|
||||
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || '/api/v1'
|
||||
const DEFAULT_API_BASE_URL = '/api/v1'
|
||||
const API_BASE_URL = normalizeAPIBaseURL(import.meta.env.VITE_API_BASE_URL)
|
||||
|
||||
function normalizePath(path: string): string {
|
||||
return path.startsWith('/') ? path : `/${path}`
|
||||
}
|
||||
|
||||
function normalizeAPIBaseURL(value: unknown): string {
|
||||
const raw = String(value || DEFAULT_API_BASE_URL).trim() || DEFAULT_API_BASE_URL
|
||||
const withoutTrailingSlash = raw.replace(/\/+$/, '')
|
||||
if (/^[a-z][a-z\d+.-]*:\/\//i.test(withoutTrailingSlash) || withoutTrailingSlash.startsWith('//')) {
|
||||
return withoutTrailingSlash
|
||||
}
|
||||
return normalizePath(withoutTrailingSlash)
|
||||
}
|
||||
|
||||
export function getAPIBaseURL(): string {
|
||||
return String(API_BASE_URL || '/api/v1')
|
||||
return API_BASE_URL
|
||||
}
|
||||
|
||||
export function buildApiUrl(path: string): string {
|
||||
const base = getAPIBaseURL().replace(/\/+$/, '')
|
||||
let suffix = normalizePath(path)
|
||||
if (suffix === '/api/v1') {
|
||||
if (suffix === DEFAULT_API_BASE_URL) {
|
||||
suffix = ''
|
||||
} else if (suffix.startsWith('/api/v1/')) {
|
||||
suffix = suffix.slice('/api/v1'.length)
|
||||
} else if (suffix.startsWith(`${DEFAULT_API_BASE_URL}/`)) {
|
||||
suffix = suffix.slice(DEFAULT_API_BASE_URL.length)
|
||||
}
|
||||
return `${base}${suffix}`
|
||||
}
|
||||
|
||||
@@ -152,6 +152,7 @@ import { useRoute, useRouter } from 'vue-router'
|
||||
import { useClipboard } from '@/composables/useClipboard'
|
||||
import { useAppStore, useAuthStore } from '@/stores'
|
||||
import { apiClient } from '@/api/client'
|
||||
import { buildApiUrl } from '@/api/url'
|
||||
import {
|
||||
exchangePendingOAuthCompletion,
|
||||
persistOAuthTokenContext,
|
||||
@@ -256,8 +257,6 @@ function readPendingEmailOAuthProvider(): 'github' | 'google' | null {
|
||||
|
||||
function redirectProviderCallbackToBackend(provider: 'github' | 'google'): void {
|
||||
if (typeof window === 'undefined') return
|
||||
const apiBase = (import.meta.env.VITE_API_BASE_URL as string | undefined) || '/api/v1'
|
||||
const normalized = apiBase.replace(/\/$/, '')
|
||||
const params = new URLSearchParams()
|
||||
for (const [key, value] of Object.entries(route.query)) {
|
||||
if (Array.isArray(value)) {
|
||||
@@ -269,7 +268,7 @@ function redirectProviderCallbackToBackend(provider: 'github' | 'google'): void
|
||||
}
|
||||
}
|
||||
const suffix = params.toString() ? `?${params.toString()}` : ''
|
||||
window.location.href = `${normalized}/auth/oauth/${provider}/callback${suffix}`
|
||||
window.location.href = buildApiUrl(`/auth/oauth/${provider}/callback${suffix}`)
|
||||
}
|
||||
|
||||
async function finalizeTokenResponse(tokenResponse: OAuthTokenResponse, redirect: string) {
|
||||
|
||||
Reference in New Issue
Block a user