using System.Security.Claims; using Yh.Platform.Abstractions; using Yh.Platform.Auth; using Xunit; namespace Yh.Platform.Auth.Tests; /// CAS serviceValidate 响应 XML 用户提取对拍(对齐 Java CasServiceTicketValidator)。 public class CasServiceTicketValidatorTests { [Fact] public void 成功响应_提取cas_user() { var xml = """ zhangsan """; Assert.Equal("zhangsan", CasServiceTicketValidator.ExtractUser(xml)); } [Fact] public void 带属性容错_提取cas_user() { var xml = "lisi"; Assert.Equal("lisi", CasServiceTicketValidator.ExtractUser(xml)); } [Fact] public void 失败响应_返回null() { var xml = """ Ticket ST-1856339 not recognized """; Assert.Null(CasServiceTicketValidator.ExtractUser(xml)); } [Theory] [InlineData("")] [InlineData(null)] [InlineData("")] public void 无用户节点或空输入_返回null(string? xml) { Assert.Null(CasServiceTicketValidator.ExtractUser(xml)); } [Fact] public async Task 未配置CAS地址_抛AuthException() { var validator = new CasServiceTicketValidator(""); var ex = await Assert.ThrowsAsync(() => validator.ValidateAsync("ST-1", "http://app/cb")); Assert.Contains("cas-server-url-prefix", ex.Message); } } public class BoaUserContextTests { [Fact] public async Task 异步流内可读取_请求结束清理() { Assert.Null(BoaUserContext.Get()); Assert.Null(UserContextHolder.Get()); BoaUser? seenInChild = null; var user = new BoaUser(1001, "zhangsan", "张三"); BoaUserContext.Set(user); UserContextHolder.Set(new LoginUser("1001") { LoginName = "zhangsan", DisplayName = "张三" }); await Task.Run(() => { // AsyncLocal 值随执行上下文流入子任务 seenInChild = BoaUserContext.Get(); }); Assert.Same(user, seenInChild); Assert.Equal("zhangsan", UserContextHolder.Get()?.LoginName); BoaUserContext.Clear(); UserContextHolder.Clear(); Assert.Null(BoaUserContext.Get()); Assert.Null(UserContextHolder.Get()); } [Fact] public void LoginUser_属性封装() { var login = new LoginUser("1001") { LoginName = "zhangsan", DisplayName = "张三", AppKey = "app-001", }; Assert.Equal("1001", login.UserId); Assert.Equal("zhangsan", login.LoginName); Assert.Equal("张三", login.DisplayName); Assert.Equal("app-001", login.AppKey); } } public class UserContextMiddlewareTests { private sealed class StubProvider : IUserDetailsProvider { public BoaUser? User { get; set; } = new(1001, "zhangsan", "张三"); public Task GetByLoginNameAsync(string loginName, CancellationToken ct = default) => Task.FromResult(User); } private static HttpContext HttpContextWithLogin(string loginName) { var identity = new ClaimsIdentity("CAS"); identity.AddClaim(new Claim("loginName", loginName)); var context = new DefaultHttpContext(); context.User = new ClaimsPrincipal(identity); return context; } [Fact] public async Task 认证请求_中间件写入上下文_业务管道内可读() { var provider = new StubProvider(); BoaUser? seen = null; LoginUser? seenLogin = null; var middleware = new UserContextMiddleware(_ => { seen = BoaUserContext.Get(); seenLogin = UserContextHolder.Get(); return Task.CompletedTask; }); await middleware.InvokeAsync(HttpContextWithLogin("zhangsan"), provider); Assert.NotNull(seen); Assert.Equal(1001, seen!.Id); Assert.Equal("zhangsan", seenLogin?.LoginName); Assert.Equal("张三", seenLogin?.DisplayName); // 请求结束后必须清空,防串扰 Assert.Null(BoaUserContext.Get()); Assert.Null(UserContextHolder.Get()); } [Fact] public async Task 未认证请求_不写上下文直接放行() { var provider = new StubProvider(); var middleware = new UserContextMiddleware(_ => Task.CompletedTask); var context = new DefaultHttpContext(); // 匿名 await middleware.InvokeAsync(context, provider); Assert.Null(BoaUserContext.Get()); Assert.Null(UserContextHolder.Get()); } }