From 380e1b7d569902333df9f8341ba6767276d99953 Mon Sep 17 00:00:00 2001 From: t0ng7u Date: Thu, 25 Sep 2025 13:02:40 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=90=20fix(oauth):=20stop=20authorize?= =?UTF-8?q?=20flow=20from=20bouncing=20to=20/console;=20respect=20`next`?= =?UTF-8?q?=20and=20redirect=20unauthenticated=20users=20to=20consent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem - Starting OAuth from Discourse hit GET /api/oauth/authorize and 302’d to /login?next=/oauth/consent… - The login page and AuthRedirect always navigated to /console when a session existed, ignoring next, which aborted the OAuth flow and dropped users in the console. Changes - Backend (src/oauth/server.go) - When not logged in, redirect directly to /oauth/consent? instead of /login?next=… - Keep no-store headers; preserve the original authorize querystring. - Frontend - web/src/helpers/auth.jsx: AuthRedirect now honors the login page’s next query param and only redirects to safe internal paths (starts with “/”, not “//”); otherwise falls back to /console. - web/src/components/auth/LoginForm.jsx: After successful login and after 2FA success, navigate to next when present and safe; otherwise go to /console. Result - The OAuth authorize flow now reliably reaches the consent screen. - On approval, the server issues an authorization code and 302’s back to the client’s redirect_uri (e.g., Discourse), completing SSO as expected. Security - Sanitize next to avoid open-redirects by allowing only same-origin internal paths. Compatibility - No behavior change for normal username/password sign-ins outside the OAuth flow. - No changes to token/userinfo endpoints. Testing - Manually verified end-to-end with Discourse OAuth2 Basic: - authorize → consent → approve → redirect with code - Lint checks pass for modified files. --- src/oauth/server.go | 23 +++++++++++------------ web/src/components/auth/LoginForm.jsx | 11 +++++++++-- web/src/helpers/auth.jsx | 6 +++++- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/oauth/server.go b/src/oauth/server.go index 87c04a5c2..3be24941e 100644 --- a/src/oauth/server.go +++ b/src/oauth/server.go @@ -846,18 +846,17 @@ func HandleAuthorizeRequest(c *gin.Context) { // 检查用户会话(要求已登录) sess := sessions.Default(c) uidVal := sess.Get("id") - if uidVal == nil { - if mode == "prepare" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "login_required"}) - return - } - // 重定向到前端登录后回到同意页 - consentPath := "/oauth/consent?" + c.Request.URL.RawQuery - loginPath := "/login?next=" + url.QueryEscape(consentPath) - writeNoStore(c) - c.Redirect(http.StatusFound, loginPath) - return - } + if uidVal == nil { + if mode == "prepare" { + c.JSON(http.StatusUnauthorized, gin.H{"error": "login_required"}) + return + } + // 直接跳转到同意页,由前端在需要时引导登录,避免已登录用户被/login重定向到/console + consentPath := "/oauth/consent?" + c.Request.URL.RawQuery + writeNoStore(c) + c.Redirect(http.StatusFound, consentPath) + return + } userID, _ := uidVal.(int) if userID == 0 { // 某些 session 库会将数字解码为 int64 diff --git a/web/src/components/auth/LoginForm.jsx b/web/src/components/auth/LoginForm.jsx index 32087ab02..b3d1d7461 100644 --- a/web/src/components/auth/LoginForm.jsx +++ b/web/src/components/auth/LoginForm.jsx @@ -176,7 +176,11 @@ const LoginForm = () => { centered: true, }); } - navigate('/console'); + // 优先跳回 next(仅允许相对路径) + const sp = new URLSearchParams(window.location.search); + const next = sp.get('next'); + const isSafeInternalPath = next && next.startsWith('/') && !next.startsWith('//'); + navigate(isSafeInternalPath ? next : '/console'); } else { showError(message); } @@ -286,7 +290,10 @@ const LoginForm = () => { setUserData(data); updateAPI(); showSuccess('登录成功!'); - navigate('/console'); + const sp = new URLSearchParams(window.location.search); + const next = sp.get('next'); + const isSafeInternalPath = next && next.startsWith('/') && !next.startsWith('//'); + navigate(isSafeInternalPath ? next : '/console'); }; // 返回登录页面 diff --git a/web/src/helpers/auth.jsx b/web/src/helpers/auth.jsx index d841afed7..b84aeeff2 100644 --- a/web/src/helpers/auth.jsx +++ b/web/src/helpers/auth.jsx @@ -36,7 +36,11 @@ export const AuthRedirect = ({ children }) => { const user = localStorage.getItem('user'); if (user) { - return ; + // 优先使用登录页上的 next 参数(仅允许站内相对路径) + const sp = new URLSearchParams(window.location.search); + const next = sp.get('next'); + const isSafeInternalPath = next && next.startsWith('/') && !next.startsWith('//'); + return ; } return children;