From b91fd1b5140a4a8564aae135ed00792f9b013789 Mon Sep 17 00:00:00 2001 From: wanghu Date: Fri, 4 Sep 2026 13:02:23 +0800 Subject: [PATCH] 1 --- .../Auth/Cas/CasAuthenticationHandler.cs | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/YhCore.WebApi/Auth/Cas/CasAuthenticationHandler.cs b/src/YhCore.WebApi/Auth/Cas/CasAuthenticationHandler.cs index 4bac20d..a41e96b 100644 --- a/src/YhCore.WebApi/Auth/Cas/CasAuthenticationHandler.cs +++ b/src/YhCore.WebApi/Auth/Cas/CasAuthenticationHandler.cs @@ -28,7 +28,8 @@ namespace YhCore.WebApi.Auth /// 调 /serviceValidate 校验(service 即登录时的原访问 URL,含分号段则一并重建,CAS 在末尾追加 /// ?ticket=/&ticket= 回跳)。成功后写入 Cookie 登录态并 302 到分号段 redirectToReferer(hex 解码, /// 当前形态)/ query redirectToReferer(旧 query 形态兼容)/ returnUrl(更早中继形态兼容)/ - /// 原 URL 去 ticket 版(无回跳目标)。 + /// 原 URL 去 ticket 版(无回跳目标);显式回跳目标(白名单通过)302 时透传一次性 ticket + /// (目标已有 query 用 &ticket=,否则 ?ticket=——按联调约定供目标页作登录完成信号)。 /// /// public class CasAuthenticationHandler : AuthenticationHandler @@ -200,19 +201,26 @@ namespace YhCore.WebApi.Auth Context.User = principal; // 回跳原地址: - // 1. query redirectToReferer=(当前形态:service=原访问 URL 时由 CAS 原样回带)→ 解码跳该目标; - // 2. query returnUrl(旧中继形态 service={回调端点}?returnUrl=… 的历史 URL/缓存,兼容); - // 3. 旧 ;redirectToReferer= 路径段(更早形态,兼容); + // 1. 路径分号段 ;redirectToReferer=(当前形态:service=原 URL;redirectToReferer=, + // CAS 原样回带)→ 解码跳该目标; + // 2. query redirectToReferer=(ff31293 前的 query 形态 URL/缓存,兼容); + // 3. query returnUrl(更早中继形态 service={回调端点}?returnUrl=…,兼容); // 4. 都没有(service=纯净原访问 URL 的 notice 形态:CAS 在 service 后追加 ?ticket= 回跳, // 本请求 Path + 除 ticket 外 query 即登录时原 URL)→ 302 去掉一次性 ticket 落回原地址。 // 允许本地相对路径或同源完整 http(s) URL;非法(外站 host / 协议相对等)回根路径,防开放重定向。 - var referer = ResolveQueryRedirectToReferer() - ?? ResolveReturnUrl() - ?? ParseRedirectToReferer(Context.Request.Path.Value); + // 显式回跳目标(1/2/3)白名单通过时透传一次性票据:目标页按联调约定可凭 ticket 自证登录成功—— + // 注意票据已被本次 /serviceValidate 消费(一次性),目标侧不得再拿去 CAS 校验,仅作登录完成信号。 + var referer = ParseRedirectToReferer(Context.Request.Path.Value) + ?? ResolveQueryRedirectToReferer() + ?? ResolveReturnUrl(); string redirect; if (referer != null) { redirect = IsAllowedReturnTarget(referer, AllowedHost()) ? referer : "/"; + if (redirect == referer) + { + redirect = AppendTicket(redirect, ticketValue); + } } else { @@ -223,6 +231,17 @@ namespace YhCore.WebApi.Auth return AuthenticateResult.NoResult(); } + /// 给回跳目标追加一次性票据(目标已有 query 用 &,否则用 ?)。 + private static string AppendTicket(string url, string ticket) + { + if (string.IsNullOrEmpty(ticket)) + { + return url; + } + return url + (url.IndexOf('?') < 0 ? "?" : "&") + + "ticket=" + Uri.EscapeDataString(ticket); + } + /// 从回调路径中解析 ;redirectToReferer= 后的 hex 并解码;无该段或编码非法返回 null。 private static string ParseRedirectToReferer(string path) {