diff --git a/src/YhCore.WebApi/Middleware/DebugUserMiddleware.cs b/src/YhCore.WebApi/Middleware/DebugUserMiddleware.cs new file mode 100644 index 0000000..ba59f7a --- /dev/null +++ b/src/YhCore.WebApi/Middleware/DebugUserMiddleware.cs @@ -0,0 +1,61 @@ +using System; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Configuration; + +namespace YhCore.WebApi.Middleware +{ + /// + /// DebugUser 模拟登录中间件(对齐老 BestSchool/Java 系统的 DebugUser 调试机制; + /// 前端 api/index.js 每次请求固定携带 DebugAppType=true 与 DebugUser=<loginName> 头)。 + /// + /// 用途:解决「本地前端(localhost:8103) 直连部署后端」的登录态跨域问题—— + /// Cookie 按 host 隔离且 SameSite=Lax 不随跨站 XHR 携带,CAS 在线上域名种下的登录态 + /// 永远无法回流 localhost 页面的请求;本中间件以请求头承载身份,绕开该物理限制。 + /// + /// 生效条件(全部满足): + /// 1. 配置开关 yh:auth:DebugUserEnabled = true(默认 false,生产环境勿开——伪造该头即可冒充任意用户); + /// 2. 当前请求未认证(正常 CAS 登录态优先,互不干扰); + /// 3. DebugAppType=true 且 DebugUser 非空。 + /// + /// 动作:按 DebugUser 值构造 loginName 身份(Claims:Name/NameIdentifier/loginName,与 CAS handler 一致), + /// 写入 Context.User。后续 UseYhUserContext 据此经 IUserDetailsProvider(UserBase /oapi/user/byLoginName) + /// 解析完整 BoaUser;loginName 无对应用户时接口返回空数据,可据此发现账号填错。 + /// + /// 注册位置:UseAuthentication 之后、SsoProtectionMiddleware 之前。 + /// + public class DebugUserMiddleware + { + private readonly RequestDelegate _next; + private readonly bool _enabled; + + public DebugUserMiddleware(RequestDelegate next, IConfiguration configuration) + { + _next = next; + _enabled = configuration.GetValue("yh:auth:DebugUserEnabled", false); + } + + public async Task InvokeAsync(HttpContext context) + { + if (_enabled + && context.User?.Identity?.IsAuthenticated != true + && string.Equals(context.Request.Headers["DebugAppType"].ToString(), "true", StringComparison.OrdinalIgnoreCase)) + { + var loginName = context.Request.Headers["DebugUser"].ToString().Trim(); + if (!string.IsNullOrEmpty(loginName)) + { + var claims = new[] + { + new Claim(ClaimTypes.Name, loginName), + new Claim(ClaimTypes.NameIdentifier, loginName), + new Claim("loginName", loginName), + }; + context.User = new ClaimsPrincipal(new ClaimsIdentity(claims, "DebugUser")); + } + } + + await _next(context); + } + } +}