ky
build / build-push (push) Successful in 1m59s

This commit is contained in:
wanghu
2026-09-03 14:43:12 +08:00
parent 02a752ad87
commit c8632e25c2
2 changed files with 37 additions and 11 deletions
@@ -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,
@@ -87,6 +87,18 @@ namespace YhCore.WebApi.Middleware
"<p><a href=\"/\">重新登录</a></p></body></html>");
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);
}
/// <summary>
/// 判断请求是否为 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、&lt;a&gt;)Accept 含 text/html 且无前两者 → false,保持 302。
/// </summary>
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;
}
/// <summary>路径是否命中保护模式(yh:sso:urlPattern / yh:sso:mobiApiPattern,默认 /api/*、/mobiapi/*,通配后缀匹配,忽略大小写)</summary>
private static bool IsProtectedPath(string path, IConfigurationSection sso)
{