-
Notifications
You must be signed in to change notification settings - Fork 0
Home
Akash Kava edited this page Apr 13, 2022
·
11 revisions
Entity Access Control is feature rich powerful alternative to GraphQL and OData. Entity Framework Core's features provide various ways to query database and create easy to read projections. We wanted clients such as browser or mobile phone apps to directly invoke these features without compromising security.
So Entity Access Control introduces set of Events and ACL Rules which allow you to control information sent to client. Just like how firewalls allow you to control your network traffic.
- Conditional Lambda Expressions for Global Filters
- Global Filters with Navigation Properties
- Global Filters for Update and Delete
- Asynchronous Events
- Auditable, implement your own
IAuditContext
- REST API Controller for accessing Entities with Security
[DIRegister(ServiceLifetime.Singleton)]
public class AppDbContextEvents: DbContextEvents<AppDbContext> {
public AppDbContextEvents() {
Register<ProjectEvents>();
Register<EmailEvents>();
}
}
/// AppDbContext is your class derived from DbContext
public class ProjectEvents: DbEntityEvents<Project> {
// You can use constructor injection
public ProjectEvents(
AppDbContext db,
IUserInfo user)
{
this.user = user;
this.db = db;
}
public override IQueryContext<Project> Filter(IQueryContext<Project> q) {
if (user.IsAuthenticated) {
if(user.IsAdmin) {
// admin can access everything
return q;
}
if(user.IsManager) {
return q.Where(x => x.AccountID == user.AccountID || x.ManagerID == user.AccountID);
}
return q.Where(x => x.AccountID == user.AccountID);
}
throw new EntityAccessException("Access to Project denied");
}
public override Task Inserting(Project entity) {
// while inserting
// we want to associate AccountID to currently logged in user id if it is not admin..
if(user.IsAdmin) {
if (entity.AccountID == 0)
entity.AccountID = user.AccountID;
} else {
entity.AccountID = user.AccountID;
}
return Task.CompletedTask;
}
}
public class EmailEvents: DbEntityEvents<Email> {
private readonly AppDbContext db;
private readonly IEmailService emailService
public EmailEvents(AppDbContext db, IEmailService emailService) {
this.db = db;
this.emailService = emailService;
}
public override IQueryContext<Email> Filter(IQueryContext<Email> q) {
if (user.IsAuthenticated) {
if(user.IsAdmin) {
// admin can access everything
return q;
}
if(user.IsManager) {
return q.Where(x => x.Project.AccountID == user.AccountID
|| x.Project.ManagerID == user.AccountID);
}
return q.Where(x => x.Project.AccountID == user.AccountID);
}
throw new EntityAccessException("Access to Email denied");
}
public async Task InsertedAsync(Email email) {
var msg = new MimeMessage();
// .. set properties ..
try {
await emailService.SendAsync(msg);
} catch (Exception ex) {
email.Error = ex.ToString();
}
email.DateSend = DateTime.UtcNow;
await db.SaveChangesWithoutEvents();
}
}
}
[Route("api/entity")]
public class EntityController: BaseEntityController<AppDbContext> {
public EntityController(AppDbContext db): base(db) {
}
}
This will expose the endpoint to access all entities. To enforce authentication, you can create rules in SecurityRules
class. You can throw an exception if user is not logged in or does not have sufficient permissions.