From 87593889607dbb42d1812271fb58059ea1a8bd47 Mon Sep 17 00:00:00 2001 From: jangrui Date: Sat, 16 May 2026 04:03:38 +0800 Subject: [PATCH] =?UTF-8?q?fix(auth):=20address=20code=20review=20issues?= =?UTF-8?q?=20=E2=80=94=20returnTo,=20timeouts,=20binding=20subject?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Preserve returnTo across SSO redirect flow: store in session at /login, restore at /callback - Configure RestTemplate connect/read timeouts (5s/10s) for SsoClient - Use immutable employee id (not mutable username) as identity binding subject; keep account as human-readable loginName --- .../skillhub/controller/SsoLoginController.java | 13 +++++++++++-- .../com/iflytek/skillhub/auth/sso/SsoClient.java | 6 +++++- .../skillhub/auth/sso/SsoIdentityService.java | 4 ++-- web/src/features/auth/sso-login-entry.tsx | 7 ++++++- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/server/skillhub-app/src/main/java/com/iflytek/skillhub/controller/SsoLoginController.java b/server/skillhub-app/src/main/java/com/iflytek/skillhub/controller/SsoLoginController.java index 733f59247..f1df8a130 100644 --- a/server/skillhub-app/src/main/java/com/iflytek/skillhub/controller/SsoLoginController.java +++ b/server/skillhub-app/src/main/java/com/iflytek/skillhub/controller/SsoLoginController.java @@ -51,11 +51,16 @@ public class SsoLoginController { * Initiates SSO login by redirecting the browser to the SSO login page. */ @GetMapping("/login") - public void ssoLogin(HttpServletResponse response) throws IOException { + public void ssoLogin(@RequestParam(value = "returnTo", required = false) String returnTo, + HttpServletRequest request, + HttpServletResponse response) throws IOException { if (!properties.isEnabled()) { response.sendError(HttpServletResponse.SC_FORBIDDEN, "SSO login is disabled"); return; } + if (returnTo != null) { + request.getSession().setAttribute("ssoReturnTo", returnTo); + } String ssoLoginUrl = UriComponentsBuilder.fromHttpUrl(properties.getBaseUrl()) .path("/login") .queryParam("clientUrl", properties.getClientUrl()) @@ -82,7 +87,11 @@ public class SsoLoginController { SsoUser ssoUser = ssoClient.validateTicket(ticket); var principal = ssoIdentityService.resolveOrCreate(ssoUser); platformSessionService.establishSession(principal, request); - response.sendRedirect("/"); + String returnTo = (String) request.getSession().getAttribute("ssoReturnTo"); + if (returnTo != null) { + request.getSession().removeAttribute("ssoReturnTo"); + } + response.sendRedirect(returnTo != null ? returnTo : "/"); } catch (TicketValidationException e) { log.warn("SSO ticket validation failed: {}", e.getMessage()); response.sendRedirect("/login?error=sso_auth_failed"); diff --git a/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/sso/SsoClient.java b/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/sso/SsoClient.java index afa770d4a..130945333 100644 --- a/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/sso/SsoClient.java +++ b/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/sso/SsoClient.java @@ -1,5 +1,6 @@ package com.iflytek.skillhub.auth.sso; +import java.time.Duration; import java.util.Map; import com.iflytek.skillhub.auth.config.SsoProperties; @@ -20,7 +21,10 @@ public class SsoClient { public SsoClient(SsoProperties properties, RestTemplateBuilder restTemplateBuilder) { this.properties = properties; - this.restTemplate = restTemplateBuilder.build(); + this.restTemplate = restTemplateBuilder + .connectTimeout(Duration.ofSeconds(5)) + .readTimeout(Duration.ofSeconds(10)) + .build(); } /** diff --git a/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/sso/SsoIdentityService.java b/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/sso/SsoIdentityService.java index 0b59cfbf2..b6696218e 100644 --- a/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/sso/SsoIdentityService.java +++ b/server/skillhub-auth/src/main/java/com/iflytek/skillhub/auth/sso/SsoIdentityService.java @@ -47,7 +47,7 @@ public class SsoIdentityService { @Transactional public PlatformPrincipal resolveOrCreate(SsoUser ssoUser) { IdentityBinding binding = bindingRepo - .findByProviderCodeAndSubject(PROVIDER_CODE, ssoUser.account()) + .findByProviderCodeAndSubject(PROVIDER_CODE, ssoUser.id()) .orElse(null); UserAccount user; @@ -69,7 +69,7 @@ public class SsoIdentityService { globalNamespaceMembershipService.ensureMember(user.getId()); binding = new IdentityBinding(user.getId(), PROVIDER_CODE, - ssoUser.account(), ssoUser.account()); + ssoUser.id(), ssoUser.account()); bindingRepo.save(binding); } diff --git a/web/src/features/auth/sso-login-entry.tsx b/web/src/features/auth/sso-login-entry.tsx index c726644c0..1d740278b 100644 --- a/web/src/features/auth/sso-login-entry.tsx +++ b/web/src/features/auth/sso-login-entry.tsx @@ -20,7 +20,12 @@ export function SsoLoginEntry() { type="button" variant="outline" onClick={() => { - window.location.href = '/api/v1/auth/sso/login' + const searchParams = new URLSearchParams(window.location.search) + const returnTo = searchParams.get('returnTo') + const loginUrl = returnTo + ? '/api/v1/auth/sso/login?returnTo=' + encodeURIComponent(returnTo) + : '/api/v1/auth/sso/login' + window.location.href = loginUrl }} > {t('login.ssoLogin')}