@@ -13,11 +13,12 @@ namespace YhCore.WebApi.Middleware
|
|||||||
/// 规则(对齐 yh:sso 配置节):
|
/// 规则(对齐 yh:sso 配置节):
|
||||||
/// - yh:sso:enabled=false(默认):所有路径匿名放行,不影响开发联调;
|
/// - yh:sso:enabled=false(默认):所有路径匿名放行,不影响开发联调;
|
||||||
/// - yh:sso:enabled=true:匹配 /api/* / /mobiapi/* / 根路径(/, 浏览器 SSO 入口) 且未认证的请求
|
/// - yh:sso:enabled=true:匹配 /api/* / /mobiapi/* / 根路径(/, 浏览器 SSO 入口) 且未认证的请求
|
||||||
/// → Challenge → Yh.Platform.Auth CasAuthenticationHandler 302 重定向到 CAS 登录页;
|
/// → Challenge → 本地化 CasAuthenticationHandler(Auth/Cas/)302 重定向到 CAS 登录页;
|
||||||
/// - CAS 回调路径(yh:sso:signInCallbackPath,默认 /signin-cas)未认证时同样 Challenge:
|
/// - CAS 回调路径(yh:sso:signInCallbackPath,默认 /api/base/GetUserInfo,回调形如
|
||||||
/// 直接访问回调(无 ticket)进入登录流程;携带失效/已消费 ticket 的回调则返回 401 错误页,
|
/// {path}[?returnUrl=<回跳地址>]&{ticket};旧形态 ;redirectToReferer=<hex> 仍兼容)未认证时同样 Challenge:
|
||||||
/// 不再次 Challenge——避免“回调→登录→新票据→再失败”无限重定向循环(自动登录型 CAS 下必现);
|
/// 直接访问回调(无 ticket)进入登录流程;携带失效/已消费 ticket 的回调则返回 401 错误页,
|
||||||
/// 回调校验成功(已认证 + 302)则短路管道,防止 MVC 端点匹配 404 覆盖 handler 的回跳 302;
|
/// 不再次 Challenge——避免“回调→登录→新票据→再失败”无限重定向循环(自动登录型 CAS 下必现);
|
||||||
|
/// 回调校验成功(已认证 + 302)则短路管道,防止 MVC 端点匹配 404 覆盖 handler 的回跳 302;
|
||||||
/// - 受保护 API 的 AJAX/XHR 请求:复用电框架 Challenge 生成 CAS 登录 URL 后改写为 200 + JSON
|
/// - 受保护 API 的 AJAX/XHR 请求:复用电框架 Challenge 生成 CAS 登录 URL 后改写为 200 + JSON
|
||||||
/// (code:302 + urlToRedirectTo),避免 XHR 跟随跨域 302 被 CORS 拦截;文档导航仍走 302;
|
/// (code:302 + urlToRedirectTo),避免 XHR 跟随跨域 302 被 CORS 拦截;文档导航仍走 302;
|
||||||
/// - Swagger 路径始终放行,方便本地接口调试;
|
/// - Swagger 路径始终放行,方便本地接口调试;
|
||||||
@@ -101,8 +102,8 @@ namespace YhCore.WebApi.Middleware
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 触发框架 Challenge 生成 CAS 登录地址(returnUrl 回跳 + URL 编码 + service 构造统一由
|
/// 触发 Challenge 生成 CAS 登录地址(本地化 CasAuthenticationHandler.BuildServiceUrl 完成
|
||||||
/// CasAuthenticationHandler.BuildServiceUrl 完成,本中间件不再手写 URL 拼接)。
|
/// service 构造:{SignInCallbackPath}[?returnUrl=<urlencoded>],回跳走 query 而非矩阵参数)。
|
||||||
/// 受保护 API 的 AJAX/XHR 请求:拦截框架写入的 302 + Location,改写为 200 + JSON,避免 XHR
|
/// 受保护 API 的 AJAX/XHR 请求:拦截框架写入的 302 + Location,改写为 200 + JSON,避免 XHR
|
||||||
/// 跟随跨域 302 跳转 CAS 登录页时被 CORS 拦截;文档导航 / 根路径 / 回调仍保持 302。
|
/// 跟随跨域 302 跳转 CAS 登录页时被 CORS 拦截;文档导航 / 根路径 / 回调仍保持 302。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -152,9 +153,22 @@ namespace YhCore.WebApi.Middleware
|
|||||||
"<p><a href=\"/\">重新登录</a></p></body></html>");
|
"<p><a href=\"/\">重新登录</a></p></body></html>");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>是否为 CAS 回调路径。</summary>
|
/// <summary>
|
||||||
|
/// 是否为 CAS 回调路径。先剥离路径矩阵参数(;xxx=yyy)再比较:
|
||||||
|
/// StartsWithSegments 按段比较,要求匹配后下一个字符是 '/' 或结束,回调若带
|
||||||
|
/// ;redirectToReferer=<hex> 后缀(旧形态)会失配,导致"已认证 + 已 302"的短路判断失效,
|
||||||
|
/// MVC 匹配不到的 404 将覆盖掉 handler 写好的回跳响应。
|
||||||
|
/// </summary>
|
||||||
private static bool IsCasCallback(PathString path, IConfigurationSection sso)
|
private static bool IsCasCallback(PathString path, IConfigurationSection sso)
|
||||||
=> path.StartsWithSegments(sso["signInCallbackPath"] ?? "/signin-cas");
|
{
|
||||||
|
var value = path.Value ?? string.Empty;
|
||||||
|
var semicolon = value.IndexOf(';');
|
||||||
|
if (semicolon >= 0)
|
||||||
|
{
|
||||||
|
value = value.Substring(0, semicolon);
|
||||||
|
}
|
||||||
|
return new PathString(value).StartsWithSegments(sso["signInCallbackPath"] ?? "/api/base/GetUserInfo");
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>响应是否已经是框架写入的 302 重定向(用于回调校验成功后短路检查)。</summary>
|
/// <summary>响应是否已经是框架写入的 302 重定向(用于回调校验成功后短路检查)。</summary>
|
||||||
private static bool IsRedirect(HttpResponse response)
|
private static bool IsRedirect(HttpResponse response)
|
||||||
|
|||||||
@@ -28,8 +28,11 @@ using YhCore.Common.Config;
|
|||||||
using YhCore.Common.Exceptions;
|
using YhCore.Common.Exceptions;
|
||||||
using YhCore.Common.UserContext;
|
using YhCore.Common.UserContext;
|
||||||
using Yh.Platform.Abstractions;
|
using Yh.Platform.Abstractions;
|
||||||
|
using Yh.Platform.AppAuth;
|
||||||
|
using Yh.Platform.OpenApi;
|
||||||
using Yh.SchClass.OpenApi;
|
using Yh.SchClass.OpenApi;
|
||||||
using Yh.Platform.Auth;
|
using Yh.Platform.Auth;
|
||||||
|
using YhCore.WebApi.Auth;
|
||||||
|
|
||||||
namespace YhCore.WebApi
|
namespace YhCore.WebApi
|
||||||
{
|
{
|
||||||
@@ -144,10 +147,14 @@ namespace YhCore.WebApi
|
|||||||
services.AddScoped<IFileService, FileService>();
|
services.AddScoped<IFileService, FileService>();
|
||||||
|
|
||||||
// ===== 基础平台(yh-platform-net 新框架,对应 Java yh-platform) =====
|
// ===== 基础平台(yh-platform-net 新框架,对应 Java yh-platform) =====
|
||||||
// 聚合注册:/oapi 客户端(Yh:Open)+ 应用签名鉴权(Yh:AppAuth)+ Cookie/CAS 认证(Yh:Sso/Yh:Auth)
|
// OpenApi 客户端(Yh:Open)+ 应用签名鉴权(Yh:AppAuth)+ 本地化 CAS 认证(Yh:Sso/Yh:Auth)。
|
||||||
// AddYhAuth 内部含 AddYhOpenApi;AddYhPlatform = AddYhAppAuth + AddYhAuth。
|
// 认证部分本地化(Auth/Cas/):service 构造为
|
||||||
|
// "{AppBaseUrl}{SignInCallbackPath}[?returnUrl=<urlencoded 回跳地址>]"(query 形态,兼容旧矩阵参数链接),
|
||||||
|
// 其余(Cookie 会话票据 / ticket 校验 / 用户上下文)与 Yh.Platform.Auth.AddYhAuth 一致。
|
||||||
// 静态门面 YschBaseOpenApi 由宿主启动时自动装配(YschFacadeWiring: IHostedService)。
|
// 静态门面 YschBaseOpenApi 由宿主启动时自动装配(YschFacadeWiring: IHostedService)。
|
||||||
services.AddYhPlatform(Configuration);
|
services.AddYhAppAuth(Configuration);
|
||||||
|
services.AddYhOpenApi(Configuration);
|
||||||
|
services.AddYhCasAuth(Configuration);
|
||||||
|
|
||||||
// 教务(SchClass)开放接口客户端 SDK(Yh.SchClass.OpenApi.dll,配置节 yh:schclass:open)
|
// 教务(SchClass)开放接口客户端 SDK(Yh.SchClass.OpenApi.dll,配置节 yh:schclass:open)
|
||||||
services.AddSchClassOpenApi(Configuration);
|
services.AddSchClassOpenApi(Configuration);
|
||||||
|
|||||||
@@ -18,9 +18,9 @@
|
|||||||
},
|
},
|
||||||
"sso": {
|
"sso": {
|
||||||
"Enabled": true,
|
"Enabled": true,
|
||||||
"CasServerUrlPrefix": "http://sso.yunhaixingtong.com/cas",
|
"CasServerUrlPrefix": "http://sso.yunhaixingtong.com",
|
||||||
"AppBaseUrl": "http://localhost:5000",
|
"AppBaseUrl": "http://localhost:51835",
|
||||||
"SignInCallbackPath": "/signin-cas",
|
"SignInCallbackPath": "/api/base/GetUserInfo",
|
||||||
"TicketValidateTimeoutMs": 10000,
|
"TicketValidateTimeoutMs": 10000,
|
||||||
"UrlPattern": "/api/*",
|
"UrlPattern": "/api/*",
|
||||||
"MobiApiPattern": "/mobiapi/*"
|
"MobiApiPattern": "/mobiapi/*"
|
||||||
|
|||||||
Reference in New Issue
Block a user