Achieve Tenant Isolation in Crud operations - adamfoneil/Dapper.CX GitHub Wiki

In a multi-tenant system, different groups of users access partitions or slices of the same underlying, shared database. In such systems, it's critical that one tenant -- that is, a group of users from one company, team, or organization -- cannot query or modify data belonging to another tenant.

There are two interfaces you can implement on your model classes that make this easy to achieve with Dapper.CX. Note that this prevents accidental or malicious cross-tenant actions, but does not prevent self-destructive actions within one's own tenant scope.

  • On your user profile model class, implement ITenantUser. This signals what tenant a user belongs to. ITenantUser<T> accepts a generic argument so you can decide the type of TenantId.

  • On models that you need to secure by TenantId, implement ITenantIsolated.

When you implement both interfaces and use the DapperCX crud service or extension methods, then all async crud operations -- gets, inserts, updates, and deletes -- are funneled through private method VerifyTenantIsolation. If the user attempting an action does not have the same TenantId as the row being affected, then an exception is thrown.

Note that the synchronous crud methods don't make use of this, however, so don't rely on these interfaces during synchronous Dapper.CX calls.

Note also that these interfaces cover crud operations only, not general-purpose querying and miscellaneous SQL statements. Please see my topic in the Dapper.QX project on this here. In a nutshell, I suggest having tenant Id criteria in queries as required query parameters. If you ever forget to set the tenant Id criteria, the worst that happens is that your query returns no data.