Language: English | Español
Get a method protected by UMS authorization in five minutes. Assumes you already have a UMS tenant and can call POST /api/v1/client/authenticate.
For full reference, see README.md.
dotnet add package Ums.Sdk.Authorization
dotnet add package Ums.Sdk.Authorization.AopFor tests:
dotnet add package Ums.Sdk.Authorization.TestingIn Program.cs:
using Ums.Sdk.Authorization;
using Ums.Sdk.Authorization.Aop;
using BeyondNetCode.Shell.DI;
builder.Services.AddAop(aop => aop
.AddAspect<AuthorizationAspect>());
builder.Services.AddUmsSdkAuthorization(); // validator + default accessor
builder.Services.AddHttpContextAuthGraphAccessor(); // ASP.NET Core integrationAdd the middleware that decodes the JWT body and stores the graph in HttpContext.Items:
app.UseUmsAuthGraph(); // before UseAuthorizationThis middleware:
- Reads the
Authorization: Bearer ...header. - Calls
POST /api/v1/client/authenticateif no cached graph or the cached one expired. - Stores the parsed
AuthorizationGraphinHttpContext.Items["UmsAuthGraph"]. - Validates
schemaVersionagainst the SDK's compatibility range; rejects with401onAUTH_205.
Add an attribute to the interface method:
public interface IOrderService
{
[RequiresScope("PURCHASE_ORDER.APPROVE")]
Task<Result> ApproveOrderAsync(Guid orderId);
}
public class OrderService : IOrderService
{
public async Task<Result> ApproveOrderAsync(Guid orderId)
{
// your business logic — runs only if authorized
return Result.Success();
}
}Register the AOP-proxied service:
builder.Services.AddAopProxy<IOrderService, OrderService>();That's it. IOrderService.ApproveOrderAsync is now protected. Calling it from an endpoint or another service:
app.MapPost("/orders/{id}/approve", async (Guid id, IOrderService svc) =>
{
var result = await svc.ApproveOrderAsync(id);
return result.IsSuccess ? Results.Ok() : Results.Forbid();
});If the authenticated user lacks PURCHASE_ORDER.APPROVE, ApproveOrderAsync throws UnauthorizedAccessException before the body runs.
[Fact]
public async Task ApproveOrder_WithoutScope_ReturnsForbidden()
{
var graph = AuthGraphBuilder
.ForTenant("LOGISTICS_CORE")
.WithUser("ana.flores@example.com")
.WithScope("PURCHASE_ORDER.VIEW") // VIEW but not APPROVE
.Build();
var accessor = new TestAuthGraphAccessor(graph);
var service = AopProxyCreator.Create<IOrderService, OrderService>(
new OrderService(),
TestAspectExecutorFactory.Create(accessor));
await Assert.ThrowsAsync<UnauthorizedAccessException>(
() => service.ApproveOrderAsync(Guid.NewGuid()));
}[RequiresScope("PURCHASE_ORDER.APPROVE", OnDenied = DenialBehavior.ReturnFailure)]
Task<Result> ApproveOrderAsync(Guid orderId);builder.Services.Configure<AuthorizationOptions>(o =>
o.Mode = AuthorizationMode.AuditOnly);Denials are logged but not blocked. Watch logs for AuthorizationDeniedEvent entries, fix gaps, then switch to Enforce.
public class OrderController(IAuthorizationValidator validator, IAuthGraphAccessor accessor)
{
public IActionResult Approve(Guid id)
{
var decision = validator.RequireScope(accessor.Current, "PURCHASE_ORDER.APPROVE");
if (decision.IsDenied) return Forbid();
// ...
}
}