EntityFrameworkCore.PolicyEnforcement
1.0.0
dotnet add package EntityFrameworkCore.PolicyEnforcement --version 1.0.0
NuGet\Install-Package EntityFrameworkCore.PolicyEnforcement -Version 1.0.0
<PackageReference Include="EntityFrameworkCore.PolicyEnforcement" Version="1.0.0" />
<PackageVersion Include="EntityFrameworkCore.PolicyEnforcement" Version="1.0.0" />
<PackageReference Include="EntityFrameworkCore.PolicyEnforcement" />
paket add EntityFrameworkCore.PolicyEnforcement --version 1.0.0
#r "nuget: EntityFrameworkCore.PolicyEnforcement, 1.0.0"
#addin nuget:?package=EntityFrameworkCore.PolicyEnforcement&version=1.0.0
#tool nuget:?package=EntityFrameworkCore.PolicyEnforcement&version=1.0.0
EntityFrameworkCore.PolicyEnforcement
๐ Introduction
A .NET library for enforcing access control policies in Entity Framework Core applications with dependency injection support.
๐ Key Features:
- ๐ Declarative Access Control: Define policies at the entity level using a fluent API
- ๐งฉ Multiple Policy Types: Support for role-based, permission-based, ownership-based, and property-based policies
- โก Automatic Enforcement: Policies applied automatically to both queries and commands
- ๐ Extensible: Build custom policy types for specific business requirements
- ๐๏ธ Clean Architecture Friendly: Designed to work well with domain-driven and clean architecture approaches
- ๐งช Testable: Easy to mock and test in isolation
- ๐ Chainable Policies: Combine multiple policies with AND/OR operators
- ๐ง Smart Caching: Performance optimized with compiled expression caching
๐ฅ Installation
dotnet add package EntityFrameworkCore.PolicyEnforcement
๐ Quick Start:
1. Configure in your DbContext
public class ApplicationDbContext : DbContext
{
public DbSet<Document> Documents { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(connectionString)
.UsePolicyEnforcement();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Document>()
.HasAccessPolicy(policy =>
policy.RequireOwnership(d => d.OwnerId)
.Or(policy.RequireRole("Admin"))
);
}
}
2. Set up the User Context
Create a class implementing IUserContext
:
public class CurrentUserContext : IUserContext
{
private readonly IHttpContextAccessor _httpContextAccessor;
public CurrentUserContext(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public string? GetCurrentUserId() =>
_httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier);
public bool IsInRole(string role) =>
_httpContextAccessor.HttpContext?.User?.IsInRole(role) ?? false;
public bool HasPermission(string permission) =>
_httpContextAccessor.HttpContext?.User?.HasClaim(c =>
c.Type == "Permission" && c.Value == permission) ?? false;
}
3. Configure in Startup
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IUserContext, CurrentUserContext>();
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
.UsePolicyEnforcement(opt =>
{
opt.EnableForQueries = true;
opt.EnableForCommands = true;
opt.ThrowOnViolation = true;
}));
}
4. Set User Context Before Operations
public class DocumentService
{
private readonly ApplicationDbContext _dbContext;
private readonly IUserContext _userContext;
public DocumentService(ApplicationDbContext dbContext, IUserContext userContext)
{
_dbContext = dbContext;
_userContext = userContext;
}
public async Task<List<Document>> GetUserDocumentsAsync()
{
// Set the user context before querying
_dbContext.SetUserContext(_userContext);
// Policy is automatically applied
return await _dbContext.Documents.ToListAsync();
}
}
Policy Types
Role-Based Policies
modelBuilder.Entity<Payroll>()
.HasAccessPolicy(policy => policy.RequireRole("HR"));
Permission-Based Policies
modelBuilder.Entity<Customer>()
.HasAccessPolicy(policy => policy.RequirePermission("customers.read"));
Ownership-Based Policies
modelBuilder.Entity<UserProfile>()
.HasAccessPolicy(policy => policy.RequireOwnership(p => p.UserId));
Property-Based Policies
modelBuilder.Entity<Document>()
.HasAccessPolicy(policy => policy.RequireProperty(d => d.IsPublic));
Combined Policies
modelBuilder.Entity<Project>()
.HasAccessPolicy(policy =>
policy.RequireOwnership(p => p.OwnerId)
.Or(policy.RequireRole("Manager"))
.Or(policy.RequireProperty(p => p.IsPublic))
);
Operation-Specific Policies
modelBuilder.Entity<Ticket>()
.HasAccessPolicy(policy => policy.RequireRole("Support"), "Default")
.HasAccessPolicy(policy => policy.RequireRole("SupportLead"), "Update")
.HasAccessPolicy(policy => policy.RequireRole("Manager"), "Delete");
Advanced Usage
Custom Policies
modelBuilder.Entity<FinancialRecord>()
.HasAccessPolicy(policy => policy.Custom(userContext =>
fr => fr.Amount < 1000 || userContext.IsInRole("FinancialApprover")
));
Self-Checking Entities
public class Team : IDefineOwnAccessPolicy
{
public int Id { get; set; }
public string Name { get; set; }
public List<TeamMember> Members { get; set; }
public bool CanAccess(IUserContext userContext, string operation)
{
var userId = userContext.GetCurrentUserId();
if (string.IsNullOrEmpty(userId)) return false;
// Allow members to read, but only admins to modify
if (operation == "Read")
return Members.Any(m => m.UserId == userId);
return Members.Any(m => m.UserId == userId && m.IsAdmin);
}
}
๐ License
This project is licensed under the MIT License. See the LICENSE file for details.
๐ Contributing
๐ฏ Found a bug or have an idea for improvement?
Feel free to open an issue or submit a pull request!
๐ GitHub Issues
โญ Support the Project
If you find this package useful, give it a star โญ on GitHub and share it with others! ๐
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. |
-
net8.0
- Microsoft.EntityFrameworkCore (>= 8.0.14)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.0.0 | 139 | a month ago |
- Initial release of EntityFrameworkCore.PolicyEnforcement.