Interface IAuthorizeResourceVia<TOwner>
- Namespace
- Trellis.Authorization
- Assembly
- Trellis.Authorization.dll
Declares resource-based authorization against a resource that is NOT the leaf resource the command identifies, but is reachable via one or more hops along IIdentifyRelatedResource<TRelated, TId> / IIdentifyRelatedResources<TRelated, TId> declarations on the entities along the path.
public interface IAuthorizeResourceVia<TOwner> : IResourceAuthorizationMessage, IAuthorizationMessage
Type Parameters
TOwnerThe resource type at the end of the navigation chain that authorization is evaluated against. The pipeline loads one or more instances of this type and passes them to Authorize(Actor, IReadOnlyList<TOwner>).
- Extension Methods
Examples
Cricket fan-out (actor owns home OR away team):
public sealed record UploadScorecardCommand(MatchId MatchId)
: ICommand<Result<Unit>>,
IIdentifyResource<Match, MatchId>,
IAuthorizeResourceVia<Team>
{
public MatchId GetResourceId() => MatchId;
public IResult Authorize(Actor actor, IReadOnlyList<Team> teams) =>
Result.Ensure(
teams.Any(t => t.CreatedByActorId == actor.Id),
new Error.Forbidden("team.not-owner"));
}
Remarks
The command identifies its leaf resource via the existing
IIdentifyResource<TResource, TId> interface (or supplies a custom
IResourceLoader<TMessage, TResource>); this interface declares only the
final authorization target. The path from leaf to TOwner is
resolved at registration time from the entity-side
IIdentifyRelatedResource<TRelated, TId> /
IIdentifyRelatedResources<TRelated, TId> declarations.
Authorize(Actor, IReadOnlyList<TOwner>) always receives IReadOnlyList<T>:
size 1 for chains whose terminal hop is singular, size N for chains whose terminal
hop is plural (fan-out, e.g. cricket "actor owns home OR away team"). The framework
does not impose the operator over the list; the command's Authorize(Actor, IReadOnlyList<TOwner>)
method picks Any, All, or any other shape.
Implementing both IAuthorizeResource<TResource> and IAuthorizeResourceVia<TOwner> on the same command is rejected at startup. Security primitives are not silently composed.
Cases not expressible by the navigation-chain model — composite keys, joins, projections, conditional / data-dependent paths, recursive hierarchies, or authorization needing multiple heterogeneous resources at once — should fall back to a custom IResourceLoader<TMessage, TResource> that returns a projection type, plus IAuthorizeResource<TResource> on the command over that projection.
Methods
Authorize(Actor, IReadOnlyList<TOwner>)
Authorizes the actor against the resolved owner resources.
IResult Authorize(Actor actor, IReadOnlyList<TOwner> owners)
Parameters
actorActorThe authenticated actor performing the operation.
ownersIReadOnlyList<TOwner>The non-null, non-empty list of resources at the end of the navigation chain. For singular-terminal chains this is always size 1; for plural-terminal chains (fan-out) it is the de-duplicated set of loaded owners. The pipeline guarantees the list is non-empty; an empty plural navigation short-circuits to Error.Forbidden before Authorize(Actor, IReadOnlyList<TOwner>) is called.
Returns
- IResult
A success result to proceed, or a failure result (typically Error.Forbidden) to short-circuit the pipeline.