修复TV端登录失效误跳/login:按路径跳转到/tv/login
This commit is contained in:
@@ -4,6 +4,7 @@ import { useEffect } from 'react';
|
|||||||
|
|
||||||
import { getAuthInfoFromBrowserCookie, clearAuthCookie } from '@/lib/auth';
|
import { getAuthInfoFromBrowserCookie, clearAuthCookie } from '@/lib/auth';
|
||||||
import { TOKEN_CONFIG } from '@/lib/refresh-token';
|
import { TOKEN_CONFIG } from '@/lib/refresh-token';
|
||||||
|
import { isLoginPathname, resolveLoginPath } from '@/lib/tv-mode';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Token 自动刷新管理器
|
* Token 自动刷新管理器
|
||||||
@@ -54,7 +55,7 @@ export function TokenRefreshManager() {
|
|||||||
// 刷新失败,先登出再跳转登录
|
// 刷新失败,先登出再跳转登录
|
||||||
if (response.status === 401 || response.status === 403) {
|
if (response.status === 401 || response.status === 403) {
|
||||||
// 如果在登录页面,跳过登出和跳转逻辑
|
// 如果在登录页面,跳过登出和跳转逻辑
|
||||||
if (window.location.pathname === '/login') {
|
if (isLoginPathname(window.location.pathname)) {
|
||||||
console.log('[Token] On login page, skipping logout and redirect');
|
console.log('[Token] On login page, skipping logout and redirect');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -69,7 +70,8 @@ export function TokenRefreshManager() {
|
|||||||
// 登出失败时清除前端cookie
|
// 登出失败时清除前端cookie
|
||||||
clearAuthCookie();
|
clearAuthCookie();
|
||||||
}
|
}
|
||||||
window.location.href = `/login?redirect=${encodeURIComponent(window.location.pathname + window.location.search)}`;
|
const loginPath = resolveLoginPath(window.location.pathname);
|
||||||
|
window.location.href = `${loginPath}?redirect=${encodeURIComponent(window.location.pathname + window.location.search)}`;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -97,6 +99,9 @@ export function TokenRefreshManager() {
|
|||||||
// Refresh Token 已过期
|
// Refresh Token 已过期
|
||||||
if (now >= authInfo.refreshExpires) {
|
if (now >= authInfo.refreshExpires) {
|
||||||
console.log('[Token] Refresh token expired, redirecting to login');
|
console.log('[Token] Refresh token expired, redirecting to login');
|
||||||
|
if (isLoginPathname(window.location.pathname)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// 先登出再跳转登录
|
// 先登出再跳转登录
|
||||||
window.fetch('/api/logout', {
|
window.fetch('/api/logout', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -106,7 +111,8 @@ export function TokenRefreshManager() {
|
|||||||
// 登出失败时清除前端cookie
|
// 登出失败时清除前端cookie
|
||||||
clearAuthCookie();
|
clearAuthCookie();
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
window.location.href = `/login?redirect=${encodeURIComponent(window.location.pathname + window.location.search)}`;
|
const loginPath = resolveLoginPath(window.location.pathname);
|
||||||
|
window.location.href = `${loginPath}?redirect=${encodeURIComponent(window.location.pathname + window.location.search)}`;
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -152,7 +158,7 @@ export function TokenRefreshManager() {
|
|||||||
// 响应拦截:401 错误时刷新 Token 并重试(仅重试一次)
|
// 响应拦截:401 错误时刷新 Token 并重试(仅重试一次)
|
||||||
if (response.status === 401) {
|
if (response.status === 401) {
|
||||||
// 如果在登录页面,跳过刷新逻辑
|
// 如果在登录页面,跳过刷新逻辑
|
||||||
if (window.location.pathname === '/login') {
|
if (isLoginPathname(window.location.pathname)) {
|
||||||
console.log('[Token] On login page, skipping refresh logic');
|
console.log('[Token] On login page, skipping refresh logic');
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
@@ -178,7 +184,7 @@ export function TokenRefreshManager() {
|
|||||||
console.error('[Token] Still 401 after refresh, redirecting to login');
|
console.error('[Token] Still 401 after refresh, redirecting to login');
|
||||||
|
|
||||||
// 如果在登录页面,跳过登出和跳转逻辑
|
// 如果在登录页面,跳过登出和跳转逻辑
|
||||||
if (window.location.pathname === '/login') {
|
if (isLoginPathname(window.location.pathname)) {
|
||||||
console.log('[Token] On login page, skipping logout and redirect');
|
console.log('[Token] On login page, skipping logout and redirect');
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
@@ -193,7 +199,8 @@ export function TokenRefreshManager() {
|
|||||||
// 登出失败时清除前端cookie
|
// 登出失败时清除前端cookie
|
||||||
clearAuthCookie();
|
clearAuthCookie();
|
||||||
}
|
}
|
||||||
window.location.href = `/login?redirect=${encodeURIComponent(window.location.pathname + window.location.search)}`;
|
const loginPath = resolveLoginPath(window.location.pathname);
|
||||||
|
window.location.href = `${loginPath}?redirect=${encodeURIComponent(window.location.pathname + window.location.search)}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
import { getAuthInfoFromBrowserCookie, clearAuthCookie } from './auth';
|
import { getAuthInfoFromBrowserCookie, clearAuthCookie } from './auth';
|
||||||
import { normalizeEpisodeFilterConfig } from './episode-filter';
|
import { normalizeEpisodeFilterConfig } from './episode-filter';
|
||||||
import { MangaReadRecord, MangaShelfItem } from './manga.types';
|
import { MangaReadRecord, MangaShelfItem } from './manga.types';
|
||||||
|
import { isLoginPathname, resolveLoginPath } from './tv-mode';
|
||||||
import { DanmakuFilterConfig, EpisodeFilterConfig, SkipConfig } from './types';
|
import { DanmakuFilterConfig, EpisodeFilterConfig, SkipConfig } from './types';
|
||||||
|
|
||||||
// 全局错误触发函数
|
// 全局错误触发函数
|
||||||
@@ -661,7 +662,7 @@ export async function fetchWithAuth(
|
|||||||
// 如果在登录页面,跳过刷新逻辑
|
// 如果在登录页面,跳过刷新逻辑
|
||||||
if (
|
if (
|
||||||
typeof window !== 'undefined' &&
|
typeof window !== 'undefined' &&
|
||||||
window.location.pathname === '/login'
|
isLoginPathname(window.location.pathname)
|
||||||
) {
|
) {
|
||||||
console.log('[fetchWithAuth] On login page, skipping refresh logic');
|
console.log('[fetchWithAuth] On login page, skipping refresh logic');
|
||||||
return res;
|
return res;
|
||||||
@@ -707,7 +708,7 @@ export async function fetchWithAuth(
|
|||||||
// 检查当前页面是否已经是登录页,避免重复跳转
|
// 检查当前页面是否已经是登录页,避免重复跳转
|
||||||
if (
|
if (
|
||||||
typeof window !== 'undefined' &&
|
typeof window !== 'undefined' &&
|
||||||
!window.location.pathname.startsWith('/login')
|
!isLoginPathname(window.location.pathname)
|
||||||
) {
|
) {
|
||||||
// 调用 logout 接口
|
// 调用 logout 接口
|
||||||
try {
|
try {
|
||||||
@@ -721,7 +722,10 @@ export async function fetchWithAuth(
|
|||||||
clearAuthCookie();
|
clearAuthCookie();
|
||||||
}
|
}
|
||||||
const currentUrl = window.location.pathname + window.location.search;
|
const currentUrl = window.location.pathname + window.location.search;
|
||||||
const loginUrl = new URL('/login', window.location.origin);
|
const loginUrl = new URL(
|
||||||
|
resolveLoginPath(window.location.pathname),
|
||||||
|
window.location.origin
|
||||||
|
);
|
||||||
loginUrl.searchParams.set('redirect', currentUrl);
|
loginUrl.searchParams.set('redirect', currentUrl);
|
||||||
window.location.href = loginUrl.toString();
|
window.location.href = loginUrl.toString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,16 @@
|
|||||||
export function isTVModeEnabled() {
|
export function isTVModeEnabled() {
|
||||||
return process.env.ENABLE_TV_MODE !== 'false';
|
return process.env.ENABLE_TV_MODE !== 'false';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isTVPathname(pathname: string): boolean {
|
||||||
|
return pathname === '/tv' || pathname.startsWith('/tv/');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 按当前路径选择登录页:TV 端走 /tv/login,其余走 /login */
|
||||||
|
export function resolveLoginPath(pathname: string): string {
|
||||||
|
return isTVPathname(pathname) ? '/tv/login' : '/login';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isLoginPathname(pathname: string): boolean {
|
||||||
|
return pathname === '/login' || pathname === '/tv/login';
|
||||||
|
}
|
||||||
|
|||||||
+2
-4
@@ -5,7 +5,7 @@ import { NextRequest, NextResponse } from 'next/server';
|
|||||||
import { isAccessTokenInvalidated } from '@/lib/access-token-invalidation';
|
import { isAccessTokenInvalidated } from '@/lib/access-token-invalidation';
|
||||||
import { getAuthInfoFromCookie } from '@/lib/auth';
|
import { getAuthInfoFromCookie } from '@/lib/auth';
|
||||||
import { TOKEN_CONFIG } from '@/lib/refresh-token';
|
import { TOKEN_CONFIG } from '@/lib/refresh-token';
|
||||||
import { isTVModeEnabled } from '@/lib/tv-mode';
|
import { isTVModeEnabled, resolveLoginPath } from '@/lib/tv-mode';
|
||||||
|
|
||||||
export async function middleware(request: NextRequest) {
|
export async function middleware(request: NextRequest) {
|
||||||
const { pathname } = request.nextUrl;
|
const { pathname } = request.nextUrl;
|
||||||
@@ -158,9 +158,7 @@ function handleAuthFailure(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TV 端页面未授权时进入电视扫码登录页
|
// TV 端页面未授权时进入电视扫码登录页
|
||||||
const loginUrl = pathname.startsWith('/tv')
|
const loginUrl = new URL(resolveLoginPath(pathname), request.url);
|
||||||
? new URL('/tv/login', request.url)
|
|
||||||
: new URL('/login', request.url);
|
|
||||||
// 保留完整的URL,包括查询参数
|
// 保留完整的URL,包括查询参数
|
||||||
const fullUrl = `${pathname}${request.nextUrl.search}`;
|
const fullUrl = `${pathname}${request.nextUrl.search}`;
|
||||||
loginUrl.searchParams.set('redirect', fullUrl);
|
loginUrl.searchParams.set('redirect', fullUrl);
|
||||||
|
|||||||
Reference in New Issue
Block a user