From c8632e25c2a12b955b21e914c47d61edb87e6b9d Mon Sep 17 00:00:00 2001 From: wanghu Date: Thu, 3 Sep 2026 14:43:12 +0800 Subject: [PATCH] ky --- .../Middleware/GlobalExceptionMiddleware.cs | 12 +------ .../Middleware/SsoProtectionMiddleware.cs | 36 +++++++++++++++++++ 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/YhCore.WebApi/Middleware/GlobalExceptionMiddleware.cs b/src/YhCore.WebApi/Middleware/GlobalExceptionMiddleware.cs index 9685e0e..0ae34f6 100644 --- a/src/YhCore.WebApi/Middleware/GlobalExceptionMiddleware.cs +++ b/src/YhCore.WebApi/Middleware/GlobalExceptionMiddleware.cs @@ -53,19 +53,9 @@ namespace YhCore.WebApi.Middleware timeNow = TimeNow() }); } - catch (Exception ex) + catch (Exception) { // 未捕获异常 → 平台兜底:200 + code:6 内部服务错误(对齐 Java GlobalExceptionHandler.handleException) - // [TEMP-DIAG 2026-09-03] 完整堆栈落 api-access 日志,定位 GetUserInfo code6 根因后移除 - try - { - log4net.LogManager.GetLogger(typeof(GlobalExceptionMiddleware)) - .Error("UNCAUGHT-EXCEPTION url=" + context.Request.Path + context.Request.QueryString + " => " + ex); - } - catch - { - // 诊断日志失败不影响响应 - } await WriteJsonAsync(context, StatusCodes.Status200OK, new { code = ErrorCode.InternalServerError.Code, diff --git a/src/YhCore.WebApi/Middleware/SsoProtectionMiddleware.cs b/src/YhCore.WebApi/Middleware/SsoProtectionMiddleware.cs index a895175..e49afe3 100644 --- a/src/YhCore.WebApi/Middleware/SsoProtectionMiddleware.cs +++ b/src/YhCore.WebApi/Middleware/SsoProtectionMiddleware.cs @@ -87,6 +87,18 @@ namespace YhCore.WebApi.Middleware "

重新登录

"); return; } + // API 渠道(/api/*、/mobiapi/*)的 AJAX/XHR 请求:未认证时返回 401 JSON,而非 302 重定向到 CAS。 + // 原因:浏览器 fetch/XHR 会跟随 302 跨域跳转到 sso.yunhaixingtong.com,而 CAS 登录页无 + // Access-Control-Allow-Origin 头,导致 CORS 拦截(Response to preflight request ... blocked)。 + // 前端据此 401 做整页跳转登录(location.href = "/")。文档导航(浏览器地址栏 / Accept:text/html)仍走 302。 + if (IsProtectedPath(context.Request.Path.Value, sso) && IsAjaxRequest(context.Request)) + { + context.Response.StatusCode = StatusCodes.Status401Unauthorized; + context.Response.ContentType = "application/json; charset=utf-8"; + await context.Response.WriteAsync("{\"code\":4,\"msg\":\"未登录\",\"data\":null}"); + return; + } + // 未认证 → Challenge → 302 重定向 CAS 登录页(ticket 校验与回跳由新框架 CasAuthenticationHandler 处理) await context.ChallengeAsync(YhAuthDefaults.CasScheme); return; @@ -95,6 +107,30 @@ namespace YhCore.WebApi.Middleware await _next(context); } + /// + /// 判断请求是否为 AJAX/XHR(而非浏览器整页文档导航)。任一命中即视为 AJAX: + /// 1. X-Requested-With: XMLHttpRequest(jQuery/axios/原生 XHR 常见); + /// 2. Sec-Fetch-Dest: empty(现代浏览器 fetch/XHR 必带); + /// 3. Accept 不含 text/html(fetch 默认 */*、axios 默认 application/json)。 + /// 文档导航(浏览器地址栏、location.href、<a>)Accept 含 text/html 且无前两者 → false,保持 302。 + /// + private static bool IsAjaxRequest(HttpRequest request) + { + if (string.Equals(request.Headers["X-Requested-With"], "XMLHttpRequest", StringComparison.OrdinalIgnoreCase)) + { + return true; + } + + if (string.Equals(request.Headers["Sec-Fetch-Dest"].ToString(), "empty", StringComparison.OrdinalIgnoreCase)) + { + return true; + } + + var accept = request.Headers["Accept"].ToString(); + return !string.IsNullOrEmpty(accept) && + accept.IndexOf("text/html", StringComparison.OrdinalIgnoreCase) < 0; + } + /// 路径是否命中保护模式(yh:sso:urlPattern / yh:sso:mobiApiPattern,默认 /api/*、/mobiapi/*,通配后缀匹配,忽略大小写) private static bool IsProtectedPath(string path, IConfigurationSection sso) {