Files
MoonTVPlus/src/app/api/auth/refresh/route.ts
2026-01-27 16:15:09 +08:00

109 lines
2.7 KiB
TypeScript

/* eslint-disable no-console */
import { NextRequest, NextResponse } from 'next/server';
import { getAuthInfoFromCookie, parseAuthInfo } from '@/lib/auth';
import { refreshAccessToken } from '@/lib/middleware-auth';
import { TOKEN_CONFIG } from '@/lib/refresh-token';
export const runtime = 'nodejs';
const STORAGE_TYPE =
(process.env.NEXT_PUBLIC_STORAGE_TYPE as
| 'localstorage'
| 'redis'
| 'upstash'
| 'kvrocks'
| undefined) || 'localstorage';
function buildRefreshResponse(authToken?: string | null) {
const body: Record<string, unknown> = { ok: true };
if (authToken) {
body.token = authToken;
const authInfo = parseAuthInfo(authToken);
if (authInfo) {
const { password, ...rest } = authInfo;
body.auth = rest;
}
}
return NextResponse.json(body);
}
export async function POST(request: NextRequest) {
const authInfo = getAuthInfoFromCookie(request);
if (!authInfo) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
if (STORAGE_TYPE === 'localstorage') {
if (!authInfo.password || authInfo.password !== process.env.PASSWORD) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const authCookie = request.cookies.get('auth');
if (!authCookie?.value) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const response = buildRefreshResponse(authCookie.value);
const expires = new Date();
expires.setDate(expires.getDate() + 60);
response.cookies.set('auth', authCookie.value, {
path: '/',
expires,
sameSite: 'lax',
httpOnly: false,
secure: false,
});
return response;
}
if (
!authInfo.username ||
!authInfo.role ||
!authInfo.timestamp ||
!authInfo.tokenId ||
!authInfo.refreshToken ||
!authInfo.refreshExpires
) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const now = Date.now();
// 只检查 Refresh Token 是否过期
if (now >= authInfo.refreshExpires) {
return NextResponse.json(
{ error: 'Refresh token expired' },
{ status: 401 }
);
}
// 只要 Refresh Token 有效,就允许刷新(即使 Access Token 已过期)
const newAuthData = await refreshAccessToken(
authInfo.username,
authInfo.role,
authInfo.tokenId,
authInfo.refreshToken,
authInfo.refreshExpires
);
if (!newAuthData) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const response = buildRefreshResponse(newAuthData);
const expires = new Date(authInfo.refreshExpires);
response.cookies.set('auth', newAuthData, {
path: '/',
expires,
sameSite: 'lax',
httpOnly: false,
secure: false,
});
return response;
}