1. Home
  2. Docs
  3. Additional Topics
  4. Integrating in Existing A...
  5. User Security and Multitenancy

User Security and Multitenancy

Dotnet Report applies data restrictions by dynamically adding conditions to the SQL WHERE clause, allowing you to filter results based on specific criteria. This article discusses how to implement “Row Level” Security and Multi-Tenancy Security by using Global Data Filters, ensuring that logged-in users only see the data they are authorized to access. By leveraging these filters, you can easily enforce user-based and tenant-based security within your reports.

In most Production Applications, you need to restrict the data available to users based on their permissions, such as limiting them to only the records they are authorized to access. For example, a user may only be able to see data for specific vendors or distributors assigned to them. Dotnet Report Builder makes it easy to apply these kinds of data restrictions using global filters based on user authentication and security claims.

This method can also be used to implement multitenancy, where different users or groups of users (tenants) are restricted to viewing only their own data.

Example Scenario: Restricting Data by Distributor

Let’s say you need to restrict a logged-in user to only viewing data for three distributors they are associated with. In your database, the DistributorID column identifies which distributor each record belongs to. The goal is to ensure that the current user only sees data where DistributorID equals 1, 2, or 3.

To automatically apply this filter when reports are generated, you can modify the GetSettings method in the ReportApiController like this:

settings.DataFilters = new { DistributorId = "1,2,3" };

This will automatically apply a filter to the SQL query that limits the data to:

WHERE ... AND [TableName].[DistributorId] IN (1,2,3)

Dynamic Filtering Based on User Claims

While the example above hardcodes the filter values, in a real-world scenario, you wouldn’t hardcode these values. Instead, you would dynamically generate the filter based on the logged-in user’s claims. For instance, the user’s accessible distributor IDs could be stored in their authentication claims, and you would extract them at runtime to apply the appropriate filter. For example:

// Retrieve the logged-in user's claims
var userClaims = User.Identity as ClaimsIdentity;

// Assume the claim "DistributorAccess" stores the distributor IDs the user can access
var distributorAccessClaim = userClaims?.FindFirst("DistributorAccess")?.Value;

// Ensure the claim is available and not empty
if (!string.IsNullOrEmpty(distributorAccessClaim))
{
    // Example claim value: "1,2,3" (Distributor IDs user can access)
    var accessibleDistributors = distributorAccessClaim.Split(',');

    // Dynamically apply the filter based on the user's accessible distributors
    settings.DataFilters = new { DistributorId = string.Join(",", accessibleDistributors) };
}

Applying Filters with Explicit Table and Column Names

If your report is pulling data from multiple tables and you need to specify exactly which table and column to apply the filter on, you can do so by using the __ (double underscore) to separate the table name and column name. For example, if the DistributorID column is in the Distributors table, you would write:

settings.DataFilters = new { Distributors__DistributorId = "1,2,3" };

This ensures that the filter is applied specifically to the DistributorID column in the Distributors table.

Applying Multiple Filters

You can also apply multiple global filters at the same time, allowing you to restrict data based on multiple conditions. For example, if you want to restrict the user to seeing only certain distributors and certain vendors, you can add both filters:

settings.DataFilters = new { DistributorId = "1,2,3", VendorId = "15,16" };

This would generate a SQL query with multiple WHERE conditions, ensuring that the user only sees data for the specified distributors and vendors.

Multitenancy Support

For applications that support multiple tenants, global filters are a powerful way to enforce data segregation between tenants. Each tenant could have its own set of records, and using these filters ensures that each user only sees the data relevant to their tenant. For example, you could filter by TenantID:

settings.DataFilters = new { TenantId = loggedInUserTenantId };

In this case, the loggedInUserTenantId would dynamically retrieve the current user’s tenant ID from their session or claims, ensuring they only see the data belonging to their tenant.

Conclusion

By applying global data filters based on user claims, you can ensure that each user only sees the data they are authorized to access. This approach not only improves security but also enables seamless support for multitenancy, where different users or tenants access their own isolated data. You can easily customize these filters to meet the needs of your specific application, whether you are working with vendors, distributors, or other entities.

How can we help?