To control data access on a per-user basis, implement the IAccessControlProvider<TEntity> interface (available in the CommunityToolkit.Datasync.Abstractions package). This provider allows you to define what data a user can see, whether they can perform specific operations, and how to modify entities before they are committed to the database.
An access control provider consists of four main parts:
GetDataView(): Returns an Expression<Func<TEntity, bool>> used to filter the data visible to the user (similar to a LINQ .Where() clause).IsAuthorizedAsync(TableOperation op, TEntity? entity, ...): Determines if the user is allowed to perform a specific TableOperation (e.g., Query, Read, Create, Update, Delete).PreCommitHookAsync(TableOperation op, TEntity entity, ...): A hook called immediately before writing to the database, useful for modifying the entity (e.g., setting a UserId).PostCommitHookAsync(TableOperation op, TEntity entity, ...): A hook called after a successful write, typically used for event management or real-time notifications rather than access control.
To use it, attach the provider to your TableController by setting its AccessControlProvider property.
public class ArticleAccessControlProvider(IHttpContextAccessor contextAccessor) : IAccessControlProvider<Article>
{
public Expression<Func<Article, bool>> GetDataView()
=> article => article.CreatedAt > DateTimeOffset.AddDays(-30);
public ValueTask<bool> IsAuthorizedAsync(TableOperation op, Article? entity, CancellationToken cancellationToken = default)
=> ValueTask.FromResult(op == TableOperation.Query || op == TableOperation.Read || IsAuthenticated);
public ValueTask PreCommitHookAsync(TableOperation op, Article entity, CancellationToken cancellationToken = default)
=> ValueTask.CompletedTask;
public ValueTask PostCommitHookAsync(TableOperation op, Article entity, CancellationToken cancellationToken = default)
=> ValueTask.CompletedTask;
}