diff --git a/uds-auth/lib/dsh-acl.js b/uds-auth/lib/dsh-acl.js index 3a8fe197..1cf717d5 100644 --- a/uds-auth/lib/dsh-acl.js +++ b/uds-auth/lib/dsh-acl.js @@ -124,12 +124,14 @@ export function resolveIdentityFromRequestSync(req, deps) { const empNo = parseCookie(cookie, 'PORTALSSOUser') || parseCookie(cookie, 'ZTEDPGSSOUser') || parseCookie(cookie, 'UDS_FALLBACK_USER') + || parseCookie(cookie, 'UDS_FALLBACK_UI') if (!empNo) return null const token = parseCookie(cookie, 'PORTALSSOCookie') || parseCookie(cookie, 'ZTEDPGSSOCookie') const isFallback = empNo === 'administrator' || !!parseCookie(cookie, 'UDS_FALLBACK_USER') + || !!parseCookie(cookie, 'UDS_FALLBACK_UI') // Bare portal empNo without token is NOT enough — otherwise logout/未登录 // still leaks workspace names via leftover SSO cookies on the WebSocket. @@ -157,6 +159,7 @@ export async function resolveIdentityFromRequest(req, deps) { const empNo = parseCookie(cookie, 'PORTALSSOUser') || parseCookie(cookie, 'ZTEDPGSSOUser') || parseCookie(cookie, 'UDS_FALLBACK_USER') + || parseCookie(cookie, 'UDS_FALLBACK_UI') if (!empNo) return null const { sessionStore, rolesStore } = deps @@ -171,6 +174,7 @@ export async function resolveIdentityFromRequest(req, deps) { || parseCookie(cookie, 'ZTEDPGSSOCookie') const isFallback = empNo === 'administrator' || !!parseCookie(cookie, 'UDS_FALLBACK_USER') + || !!parseCookie(cookie, 'UDS_FALLBACK_UI') if (!userContext) { // Require session, token, or fallback cookie — never empNo alone. diff --git a/uds-auth/lib/index.js b/uds-auth/lib/index.js index 4ecc1364..e8fc9e53 100644 --- a/uds-auth/lib/index.js +++ b/uds-auth/lib/index.js @@ -414,6 +414,14 @@ function sendJSON(res, code, data) { res.end(JSON.stringify(data)) } + +/** Prefer Secure cookies only on HTTPS — http://127.0.0.1 drops Secure cookies from WS. */ +function isHttpsRequest(req) { + if (req?.socket?.encrypted) return true + const xf = String(req?.headers?.['x-forwarded-proto'] || '').split(',')[0].trim().toLowerCase() + return xf === 'https' +} + async function handleFallbackLogin(req, res) { let body = '' for await (const chunk of req) body += chunk @@ -450,24 +458,27 @@ async function handleFallbackLogin(req, res) { // 给浏览器设 cookie,让后续请求 auth-middleware 能识别 const fbMaxAge = Math.floor(INTERNAL.session.cookieMaxAge / 1000) - res.setHeader('Set-Cookie', [ - [ + res.setHeader('Set-Cookie', (() => { + const secure = isHttpsRequest(req) + const partsUser = [ 'UDS_FALLBACK_USER=administrator', `Max-Age=${fbMaxAge}`, 'Path=/', - 'Secure', 'HttpOnly', 'SameSite=Lax', - ].join('; '), - // Readable by document.cookie so client ACL gates see fallback login before /api/me. - [ + ] + const partsUi = [ 'UDS_FALLBACK_UI=administrator', `Max-Age=${fbMaxAge}`, 'Path=/', - 'Secure', 'SameSite=Lax', - ].join('; '), - ]) + ] + if (secure) { + partsUser.push('Secure') + partsUi.push('Secure') + } + return [partsUser.join('; '), partsUi.join('; ')] + })()) sendJSON(res, 200, { success: true,