''
This commit is contained in:
34
app/lib/auth-cookie.ts
Normal file
34
app/lib/auth-cookie.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 认证 Cookie 配置
|
||||
* 生产环境设置 AUTH_COOKIE_DOMAIN 实现跨子域 SSO(如 .hackrobot.cn)
|
||||
* 本地开发不设置 domain,避免 IP 访问时 cookie 失效
|
||||
*/
|
||||
|
||||
const COOKIE_NAME = "pb_session";
|
||||
const COOKIE_MAX_AGE = 60 * 60 * 24 * 365;
|
||||
|
||||
export { COOKIE_NAME, COOKIE_MAX_AGE };
|
||||
|
||||
/** 从请求 Host 头提取 hostname(不含端口) */
|
||||
export function getHostFromRequest(request: { headers: { get: (k: string) => string | null } }): string {
|
||||
const host = request.headers.get("host") || request.headers.get("x-forwarded-host") || "";
|
||||
return host.split(",")[0].trim().replace(/:\d+$/, "");
|
||||
}
|
||||
|
||||
export function getCookieOptions(clear = false, requestHost?: string) {
|
||||
const isProd = process.env.NODE_ENV === "production";
|
||||
const domain = process.env.AUTH_COOKIE_DOMAIN?.trim();
|
||||
const opts: Record<string, unknown> = {
|
||||
path: "/",
|
||||
maxAge: clear ? 0 : COOKIE_MAX_AGE,
|
||||
secure: isProd,
|
||||
sameSite: "lax" as const,
|
||||
httpOnly: true,
|
||||
};
|
||||
if (domain && isProd) {
|
||||
opts.domain = domain;
|
||||
} else if (!isProd && requestHost && /^(\d{1,3}\.){3}\d{1,3}$/.test(requestHost)) {
|
||||
opts.domain = requestHost;
|
||||
}
|
||||
return opts;
|
||||
}
|
||||
@@ -9,9 +9,12 @@ type LocaleLinkProps = React.ComponentProps<typeof NextLink>;
|
||||
export function LocaleLink({ href, ...props }: LocaleLinkProps) {
|
||||
const locale = useLocale();
|
||||
const hrefStr = typeof href === "string" ? href : href.pathname ?? "/";
|
||||
const localeHref = hrefStr.startsWith("/")
|
||||
? `/${locale}${hrefStr === "/" ? "" : hrefStr}`
|
||||
: hrefStr;
|
||||
const localeHref =
|
||||
hrefStr.startsWith("/api/") || hrefStr.startsWith("/_next")
|
||||
? hrefStr
|
||||
: hrefStr.startsWith("/")
|
||||
? `/${locale}${hrefStr === "/" ? "" : hrefStr}`
|
||||
: hrefStr;
|
||||
return <NextLink href={localeHref} {...props} />;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ export function useAuthAndVip(): AuthAndVipState {
|
||||
let newUser = meData?.user ?? null;
|
||||
let newVip = vipData?.vip === true;
|
||||
|
||||
// 与 Header 一致:API 无用户时,尝试从 localStorage 恢复(如 cookie 未同步、localhost 开发等)
|
||||
if (!newUser) {
|
||||
const storedUser = getStoredUser();
|
||||
const storedToken = getStoredToken();
|
||||
|
||||
5
app/lib/useCrossSiteUrls.ts
Normal file
5
app/lib/useCrossSiteUrls.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { MEETUP_URL, VIP_URL } from "@/config/domain.config";
|
||||
|
||||
export function useCrossSiteUrls(): { meetupUrl: string; vipUrl: string } {
|
||||
return { meetupUrl: MEETUP_URL, vipUrl: VIP_URL };
|
||||
}
|
||||
Reference in New Issue
Block a user