1
build / build-push (push) Successful in 1m14s

This commit is contained in:
wanghu
2026-09-04 09:58:52 +08:00
parent b7789a1914
commit 9fe45c810e
5 changed files with 532 additions and 0 deletions
@@ -0,0 +1,81 @@
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Yh.Platform.Auth;
namespace YhCore.WebApi.Auth
{
/// <summary>
/// 轻量 CAS service ticket 校验器(对齐 Java CasServiceTicketValidator,不依赖 CAS 客户端库)。
/// 调用 CAS 的 /serviceValidate 端点,从响应 XML 中提取 &lt;cas:user&gt;。
/// </summary>
public class CasServiceTicketValidator
{
private readonly string _casServerUrl;
private readonly int _timeoutMs;
public CasServiceTicketValidator(string casServerUrl, int timeoutMs = 5000)
{
_casServerUrl = casServerUrl;
_timeoutMs = timeoutMs > 0 ? timeoutMs : 5000;
}
/// <summary>校验 ticket,成功返回登录账号,失败/无效返回 null。</summary>
public async Task<string> ValidateAsync(string ticket, string service, CancellationToken ct = default)
{
if (string.IsNullOrWhiteSpace(_casServerUrl))
{
throw new AuthException("未配置 CasServerUrlPrefix(yh:sso:cas-server-url-prefix),无法进行 ticket 校验");
}
var base_ = _casServerUrl.EndsWith('/') ? _casServerUrl : _casServerUrl + "/";
var endpoint = base_ + "serviceValidate"
+ "?ticket=" + Uri.EscapeDataString(ticket ?? "")
+ "&service=" + Uri.EscapeDataString(service ?? "");
try
{
using var handler = new SocketsHttpHandler { ConnectTimeout = TimeSpan.FromMilliseconds(_timeoutMs) };
using var http = new HttpClient(handler) { Timeout = TimeSpan.FromMilliseconds(_timeoutMs) };
using var resp = await http.GetAsync(endpoint, ct).ConfigureAwait(false);
var body = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false);
if (!resp.IsSuccessStatusCode || body == null)
{
return null;
}
return ExtractUser(body);
}
catch (Exception e) when (e is HttpRequestException or TaskCanceledException)
{
throw new AuthException("CAS serviceValidate 请求失败: " + e.Message, e);
}
}
/// <summary>
/// 从 CAS 响应 XML 提取用户名。
/// 成功响应形如 &lt;cas:serviceResponse&gt;&lt;cas:authenticationSuccess&gt;&lt;cas:user&gt;NAME&lt;/cas:user&gt;...
/// </summary>
public static string ExtractUser(string xml)
{
if (string.IsNullOrEmpty(xml))
{
return null;
}
var start = xml.IndexOf("<cas:user>", StringComparison.Ordinal);
if (start < 0)
{
start = xml.IndexOf("<cas:user ", StringComparison.Ordinal); // 容错带属性
}
if (start < 0)
{
return null;
}
var tagEnd = xml.IndexOf('>', start);
var end = xml.IndexOf("</cas:user>", tagEnd, StringComparison.Ordinal);
if (tagEnd < 0 || end < 0)
{
return null;
}
return xml.Substring(tagEnd + 1, end - tagEnd - 1).Trim();
}
}
}