From 64b14dc7d394cc180a5e82081c2305c3975667e9 Mon Sep 17 00:00:00 2001 From: selfrelease Date: Thu, 9 Jul 2026 01:08:34 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=99=BB=E5=BD=95401?= =?UTF-8?q?=E5=92=8C=E5=88=87=E6=8D=A2=E6=9C=BA=E6=9E=84=E5=A4=B1=E8=B4=A5?= =?UTF-8?q?=20-=20Cookie=20Secure=E6=94=B9=E4=B8=BA=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E5=88=A4=E6=96=AD=20+=20=E9=BB=98=E8=AE=A4=E9=82=AE=E7=AE=B1?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/src/app/(auth)/login/login-form.tsx | 2 +- server/internal/handler/auth.go | 40 ++++++++++++++++---- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/apps/web/src/app/(auth)/login/login-form.tsx b/apps/web/src/app/(auth)/login/login-form.tsx index dd6ee36..d3d6ba3 100644 --- a/apps/web/src/app/(auth)/login/login-form.tsx +++ b/apps/web/src/app/(auth)/login/login-form.tsx @@ -20,7 +20,7 @@ import { } from "lucide-react"; export default function LoginForm({ initialOrgs }: { initialOrgs: Organization[] }) { - const [email, setEmail] = useState("fazhiribao@govai.gov.cn"); + const [email, setEmail] = useState("fazhiwang@govai.gov.cn"); const [password, setPassword] = useState("admin123"); const [loading, setLoading] = useState(false); const [errorMsg, setErrorMsg] = useState(""); diff --git a/server/internal/handler/auth.go b/server/internal/handler/auth.go index a597de8..4c75f3b 100644 --- a/server/internal/handler/auth.go +++ b/server/internal/handler/auth.go @@ -18,6 +18,12 @@ type AuthHandler struct { jwtMgr *auth.JWTManager } +// isSecureCookie 根据请求协议判断是否启用 Secure 标志 +// HTTPS 请求启用 Secure,HTTP(localhost 开发环境)不启用,避免浏览器拒绝 Cookie +func isSecureCookie(r *http.Request) bool { + return r.TLS != nil || r.Header.Get("X-Forwarded-Proto") == "https" +} + func NewAuthHandler(pool *pgxpool.Pool, jwtMgr *auth.JWTManager) *AuthHandler { return &AuthHandler{pool: pool, jwtMgr: jwtMgr} } @@ -100,7 +106,7 @@ func (h *AuthHandler) Register(w http.ResponseWriter, r *http.Request) { Value: tokenPair.AccessToken, Path: "/", HttpOnly: true, - Secure: true, + Secure: isSecureCookie(r), SameSite: http.SameSiteLaxMode, MaxAge: int(24 * time.Hour / time.Second), }) @@ -184,7 +190,7 @@ func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) { Value: tokenPair.AccessToken, Path: "/", HttpOnly: true, - Secure: true, + Secure: isSecureCookie(r), SameSite: http.SameSiteLaxMode, MaxAge: int(24 * time.Hour / time.Second), }) @@ -193,7 +199,7 @@ func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) { Value: tokenPair.RefreshToken, Path: "/api/v1/auth/refresh", HttpOnly: true, - Secure: true, + Secure: isSecureCookie(r), SameSite: http.SameSiteLaxMode, MaxAge: int(7 * 24 * time.Hour / time.Second), }) @@ -219,7 +225,7 @@ func (h *AuthHandler) Logout(w http.ResponseWriter, r *http.Request) { Value: "", Path: "/", HttpOnly: true, - Secure: true, + Secure: isSecureCookie(r), SameSite: http.SameSiteLaxMode, MaxAge: -1, }) @@ -228,7 +234,7 @@ func (h *AuthHandler) Logout(w http.ResponseWriter, r *http.Request) { Value: "", Path: "/api/v1/auth/refresh", HttpOnly: true, - Secure: true, + Secure: isSecureCookie(r), SameSite: http.SameSiteLaxMode, MaxAge: -1, }) @@ -323,12 +329,32 @@ func (h *AuthHandler) SwitchOrg(w http.ResponseWriter, r *http.Request) { } // 为目标用户生成新的JWT token(通过 HttpOnly Cookie 设置) - _, err = h.jwtMgr.GenerateTokenPair(targetID, targetEmail, targetRole) + tokenPair, err := h.jwtMgr.GenerateTokenPair(targetID, targetEmail, targetRole) if err != nil { response.InternalError(w, "生成令牌失败") return } + // 更新 Cookie 中的 token,使切换立即生效 + http.SetCookie(w, &http.Cookie{ + Name: "access_token", + Value: tokenPair.AccessToken, + Path: "/", + HttpOnly: true, + Secure: isSecureCookie(r), + SameSite: http.SameSiteLaxMode, + MaxAge: int(24 * time.Hour / time.Second), + }) + http.SetCookie(w, &http.Cookie{ + Name: "refresh_token", + Value: tokenPair.RefreshToken, + Path: "/api/v1/auth/refresh", + HttpOnly: true, + Secure: isSecureCookie(r), + SameSite: http.SameSiteLaxMode, + MaxAge: int(7 * 24 * time.Hour / time.Second), + }) + org := h.loadOrgInfo(r.Context(), req.OrgID) response.JSON(w, http.StatusOK, map[string]any{ "message": "已切换", @@ -413,7 +439,7 @@ func (h *AuthHandler) Refresh(w http.ResponseWriter, r *http.Request) { Value: tokenPair.AccessToken, Path: "/", HttpOnly: true, - Secure: true, + Secure: isSecureCookie(r), SameSite: http.SameSiteLaxMode, MaxAge: int(24 * time.Hour / time.Second), })