修复公网免登会话Cookie判定

This commit is contained in:
chenpei 2026-07-07 13:31:01 +08:00
parent c79414dcac
commit fcc8787374
2 changed files with 44 additions and 7 deletions

View File

@ -7,6 +7,14 @@ import {
} from '@/lib/auth-cookie'
describe('auth cookie protocol resolution', () => {
function restoreEnv(name: string, value: string | undefined) {
if (value === undefined) {
delete process.env[name]
} else {
process.env[name] = value
}
}
it('HTTPS 请求使用 secure cookie', () => {
expect(
resolveSecureAuthCookieFromRequest({
@ -30,6 +38,31 @@ describe('auth cookie protocol resolution', () => {
).toBe(false)
})
it('公网域名经过内网 HTTP 反代时仍使用 secure cookie', () => {
const originalAppPublicUrl = process.env.APP_PUBLIC_URL
const originalNextAuthUrl = process.env.NEXTAUTH_URL
process.env.APP_PUBLIC_URL = 'https://sc.jiansun.vip'
process.env.NEXTAUTH_URL = 'https://sc.jiansun.vip'
jest.isolateModules(() => {
const {
resolveSecureAuthCookieFromRequest: resolveWithPublicHost,
} = require('@/lib/auth-cookie')
expect(
resolveWithPublicHost({
headers: {
host: 'sc.jiansun.vip',
'x-forwarded-proto': 'http',
},
})
).toBe(true)
})
restoreEnv('APP_PUBLIC_URL', originalAppPublicUrl)
restoreEnv('NEXTAUTH_URL', originalNextAuthUrl)
})
it('优先和兜底 cookie 名称都可返回', () => {
expect(getAuthSessionCookieName(true)).toBe(SECURE_AUTH_SESSION_COOKIE_NAME)
expect(getAuthSessionCookieName(false)).toBe(PLAIN_AUTH_SESSION_COOKIE_NAME)

View File

@ -104,24 +104,28 @@ function resolveSecureCookieFromPublicBase(headersLike?: HeaderAccessor, url?: s
const publicUrl = new URL(AUTH_COOKIE_BASE_URL)
const forwardedHost = getHeaderValue(headersLike, 'x-forwarded-host')
const host = forwardedHost || getHeaderValue(headersLike, 'host') || (url ? new URL(url).host : '')
if (!host) {
return null
}
return !host || host === publicUrl.host
const normalizedHost = host.split(',')[0].trim().toLowerCase()
return normalizedHost === publicUrl.host.toLowerCase() ? true : null
} catch {
return true
return null
}
}
export function resolveSecureAuthCookieFromRequest(request?: RequestLike) {
const secureFromPublicBase = resolveSecureCookieFromPublicBase(request?.headers, request?.url)
if (secureFromPublicBase === true) {
return true
}
const protocolFromHeaders = resolveProtocolFromHeaders(request?.headers)
if (protocolFromHeaders) {
return protocolFromHeaders === 'https'
}
const secureFromPublicBase = resolveSecureCookieFromPublicBase(request?.headers, request?.url)
if (secureFromPublicBase !== null) {
return secureFromPublicBase
}
const protocolFromNextUrl = normalizeProtocol(request?.nextUrl?.protocol)
if (protocolFromNextUrl) {
return protocolFromNextUrl === 'https'