Files
DocprintService/src/YhCore.WebApi/Auth/Cas/CasServiceTicketValidator.cs
T
wanghu 9fe45c810e
build / build-push (push) Successful in 1m14s
1
2026-09-04 09:58:52 +08:00

82 lines
3.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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();
}
}
}