Table of Contents

Class TeamAccessInterceptor

Namespace
Tharga.Team.Service
Assembly
Tharga.Team.Service.dll

Refuses any database operation that no authorization decision covers.

public sealed class TeamAccessInterceptor : ICollectionInterceptor
Inheritance
TeamAccessInterceptor
Implements
ICollectionInterceptor
Inherited Members

Remarks

Defence in depth, not the primary control — AddTeamService / AddSystemService are what authorize a call. This catches the case those cannot: code that reaches the database without going through the authorization layer at all, including a consumer's own repositories, which Tharga.Team never sees. Register it with:

builder.AddMongoDB(o => o.AddCollectionInterceptor<TeamAccessInterceptor>());

It runs at Tharga.MongoDB.Interception.InterceptionPoint.Invocation only. At Tharga.MongoDB.Interception.InterceptionPoint.Enumeration a deferred operation's work happens when the consumer enumerates, potentially long after the authorizing scope has disposed — checking there would reject legitimate calls and push people towards widening scopes until the guard meant nothing.

It asserts that a decision was made, not that the right one was: at this layer the entity being touched carries no team, so there is nothing to compare a team key against. Binding a scope to the team named in the call is ScopeProxy's job.

Properties

Points

Which point(s) in an operation's lifetime this interceptor wants to run at. Defaults to Tharga.MongoDB.Interception.InterceptionPoint.Invocation, which is what a policy gate wants; override only to opt into Tharga.MongoDB.Interception.InterceptionPoint.Enumeration as well.

public InterceptionPoint Points { get; }

Property Value

InterceptionPoint

Methods

BeforeCallAsync(CollectionCallInfo, CancellationToken)

Called before the operation runs. Return Tharga.MongoDB.Interception.InterceptDecision.Proceed to allow it, or Reject(string) to block it.

Throwing also blocks the operation, and the exception propagates to the caller unchanged. Prefer Reject(string) — it gives callers a single documented exception type to catch — and throw only when a meaningful domain exception already exists and laundering it through a string reason would lose information.

This runs on the operation's hot path. Keep it cheap, and do not call back into a repository collection from here.

public ValueTask<InterceptDecision> BeforeCallAsync(CollectionCallInfo call, CancellationToken cancellationToken = default)

Parameters

call CollectionCallInfo

What is about to run.

cancellationToken CancellationToken

The cancellation token of the intercepted operation.

Returns

ValueTask<InterceptDecision>