Auth session 持久化 + 多分辨率跑道图表 + 拖拽缩放
- middleware: refreshMiddlewareSession 前置刷新 Supabase token - backend-auth: getUser() 优先触发 refresh,再 getSession 拿新 token - Dashboard: onAuthStateChange 实时更新 proAccess + 15min getSession 心跳 - detail proxy: 新增 city/[name]/detail 代理,透传 resolution 参数 - city_payloads: aggregate_runway_history + build_runway_band_history 跑道聚合 - chart: 10m→1m 自适应分辨率 + zoom 拖拽 + 跑道温区 Area + Runway Details 开关
This commit is contained in:
@@ -41,19 +41,14 @@ export async function buildBackendRequestHeaders(
|
||||
const incomingAuth = extractBearerToken(request.headers.get("authorization"));
|
||||
const includeSupabaseIdentity = options?.includeSupabaseIdentity !== false;
|
||||
if (hasSupabaseServerEnv() && includeSupabaseIdentity) {
|
||||
const supabase = createSupabaseRouteClient(request, new NextResponse(null, { status: 200 }));
|
||||
const {
|
||||
data: { session },
|
||||
} = await supabase.auth.getSession();
|
||||
let user = session?.user ?? null;
|
||||
if (session) {
|
||||
const {
|
||||
data: { user: validated },
|
||||
} = await supabase.auth.getUser();
|
||||
user = validated ?? session.user;
|
||||
}
|
||||
|
||||
const passthroughResponse = new NextResponse(null, { status: 200 });
|
||||
const supabase = createSupabaseRouteClient(request, passthroughResponse);
|
||||
|
||||
// Always call getUser() to ensure token is validated and refreshed if expired
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser();
|
||||
|
||||
const forwardedUserId = String(user?.id || "").trim();
|
||||
const forwardedEmail = String(user?.email || "").trim();
|
||||
if (forwardedUserId) {
|
||||
@@ -67,6 +62,11 @@ export async function buildBackendRequestHeaders(
|
||||
headers.set("Authorization", `Bearer ${incomingAuth}`);
|
||||
return { headers, response: passthroughResponse, authUserId: forwardedUserId || null, authEmail: forwardedEmail || null };
|
||||
}
|
||||
|
||||
// Call getSession() to get the updated access token (after getUser() has refreshed it if needed)
|
||||
const {
|
||||
data: { session },
|
||||
} = await supabase.auth.getSession();
|
||||
const accessToken = session?.access_token || "";
|
||||
if (accessToken) {
|
||||
// Fallback to cookie-backed session when request does not carry bearer.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createServerClient, type CookieOptions } from "@supabase/ssr";
|
||||
import type { NextRequest, NextResponse } from "next/server";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
type CookieAdapter = {
|
||||
getAll: () => { name: string; value: string }[];
|
||||
@@ -68,3 +68,46 @@ export function createSupabaseRouteClient(
|
||||
});
|
||||
}
|
||||
|
||||
export async function refreshMiddlewareSession(request: NextRequest) {
|
||||
let response = NextResponse.next({
|
||||
request: {
|
||||
headers: request.headers,
|
||||
},
|
||||
});
|
||||
|
||||
if (!hasSupabaseServerEnv()) {
|
||||
return { response, user: null };
|
||||
}
|
||||
|
||||
const supabase = createSupabaseServerClient({
|
||||
getAll() {
|
||||
return request.cookies.getAll().map((item) => ({
|
||||
name: item.name,
|
||||
value: item.value,
|
||||
}));
|
||||
},
|
||||
setAll(cookiesToSet) {
|
||||
for (const cookie of cookiesToSet) {
|
||||
request.cookies.set(cookie.name, cookie.value);
|
||||
}
|
||||
response = NextResponse.next({
|
||||
request: {
|
||||
headers: request.headers,
|
||||
},
|
||||
});
|
||||
for (const cookie of cookiesToSet) {
|
||||
response.cookies.set(cookie.name, cookie.value, cookie.options);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser();
|
||||
return { response, user };
|
||||
} catch {
|
||||
return { response, user: null };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user