核心功能: - 公告状态机(草稿/已发布/已撤销)支持发布、撤销和重新发布 - 发布者范围区分平台级和租户级公告 - 目标受众定向推送(全部租户/指定角色/指定用户) - 平台管理、租户管理和应用端查询API - 已读/未读管理和未读统计 技术实现: - CQRS+DDD架构,清晰的领域边界和事件驱动 - 查询性能优化:数据库端排序和限制,估算策略减少内存占用 - 并发控制:修复RowVersion配置(IsRowVersion→IsConcurrencyToken) - 完整的FluentValidation验证器和输入保护 测试验证: - 36个测试全部通过(27单元+9集成) - 性能测试达标(1000条数据<5秒) - 代码质量评级A(优秀) 文档: - 完整的ADR、API文档和迁移指南 - 交付报告和技术债务记录
81 lines
3.2 KiB
C#
81 lines
3.2 KiB
C#
using System.Security.Claims;
|
|
using FluentAssertions;
|
|
using Microsoft.AspNetCore.Authentication;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Authorization.Policy;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using TakeoutSaaS.Module.Authorization.Policies;
|
|
|
|
namespace TakeoutSaaS.Integration.Tests.Authorization;
|
|
|
|
public sealed class PermissionAuthorizationHandlerTests
|
|
{
|
|
[Theory]
|
|
[InlineData("platform-announcement:create")]
|
|
[InlineData("platform-announcement:publish")]
|
|
[InlineData("platform-announcement:revoke")]
|
|
[InlineData("tenant-announcement:publish")]
|
|
[InlineData("tenant-announcement:revoke")]
|
|
public async Task GivenUserWithPermission_WhenAuthorize_ThenSucceeds(string permission)
|
|
{
|
|
// Arrange
|
|
var requirement = new PermissionRequirement(new[] { permission });
|
|
var identity = new ClaimsIdentity(new[]
|
|
{
|
|
new Claim(PermissionAuthorizationHandler.PermissionClaimType, permission)
|
|
}, "Test");
|
|
var user = new ClaimsPrincipal(identity);
|
|
var context = new AuthorizationHandlerContext(new[] { requirement }, user, null);
|
|
var handler = new PermissionAuthorizationHandler();
|
|
|
|
// Act
|
|
await handler.HandleAsync(context);
|
|
|
|
// Assert
|
|
context.HasSucceeded.Should().BeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GivenUserWithoutPermission_WhenAuthorize_ThenFails()
|
|
{
|
|
// Arrange
|
|
var requirement = new PermissionRequirement(new[] { "platform-announcement:create" });
|
|
var user = new ClaimsPrincipal(new ClaimsIdentity(authenticationType: "Test"));
|
|
var context = new AuthorizationHandlerContext(new[] { requirement }, user, null);
|
|
var handler = new PermissionAuthorizationHandler();
|
|
|
|
// Act
|
|
await handler.HandleAsync(context);
|
|
|
|
// Assert
|
|
context.HasSucceeded.Should().BeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GivenAuthenticatedUserWithoutPermission_WhenEvaluatingPolicy_ThenForbidden()
|
|
{
|
|
// Arrange
|
|
var services = new ServiceCollection();
|
|
services.AddAuthorization();
|
|
services.AddSingleton<IAuthorizationPolicyProvider, PermissionAuthorizationPolicyProvider>();
|
|
services.AddSingleton<IAuthorizationHandler, PermissionAuthorizationHandler>();
|
|
var provider = services.BuildServiceProvider();
|
|
|
|
var policyProvider = provider.GetRequiredService<IAuthorizationPolicyProvider>();
|
|
var policy = await policyProvider.GetPolicyAsync(
|
|
PermissionAuthorizationPolicyProvider.BuildPolicyName(new[] { "platform-announcement:create" }));
|
|
|
|
var user = new ClaimsPrincipal(new ClaimsIdentity(authenticationType: "Test"));
|
|
var authenticateResult = AuthenticateResult.Success(new AuthenticationTicket(user, "Test"));
|
|
var httpContext = new DefaultHttpContext { RequestServices = provider, User = user };
|
|
var evaluator = provider.GetRequiredService<IPolicyEvaluator>();
|
|
|
|
// Act
|
|
var result = await evaluator.AuthorizeAsync(policy!, authenticateResult, httpContext, resource: null);
|
|
|
|
// Assert
|
|
result.Forbidden.Should().BeTrue();
|
|
}
|
|
}
|