In my current project I have a Report
class, and I am going to implement a service layer for it. Every method will be allowed only for some roles. Like this:
public class ReportService : IReportService
{
public void CreateReport(Report report, User user)
{
if(user.HasRole("Admin"))
{
throw new SecurityException("You do not have permissions to do it");
}
...
}
public void ModifyReport(Report report, User user)
{
if(user.HasRole("Admin"))
{
throw new SecurityException("You do not have permissions to do it");
}
...
}
public bool ValidateReport(Report report, User user)
{
if (!user.HasRole("Manager"))
{
throw new SecurityException("You do not have permissions to do it");
}
}
public void DeleteReport(Report report, User user)
{
if (user.HasRole("Employee") || user.HasRole("Manager"))
{
throw new SecurityException("You do not have permissions to do it");
}
...
}
}
Is this straightforward approach OK? Do you have some better ideas?
I have just an idea to implement it as the decorator pattern, so the code will be like this:
public class ReportService : IReportService
{
public void CreateReport(Report report, User user)
{
// Actual implementation
}
public void ModifyReport(Report report, User user)
{
// Actual implementation
}
public bool ValidateReport(Report report, User user)
{
// Actual implementation
}
public void DeleteReport(Report report, User user)
{
// Actual implementation
}
}
public class PermissionsReportService : IReportService
{
private IReportSerivce _service;
public PermissionsReportService(IReportService service)
{
_service = service;
}
public void CreateReport(Report report, User user)
{
if (user.HasRole("Admin"))
{
throw new SecurityException("You do not have permissions to do it");
}
_service.CreateReport(report, user);
}
public void ModifyReport(Report report, User user)
{
if (user.HasRole("Admin"))
{
throw new SecurityException("You do not have permissions to do it");
}
_service.ModifyReport(report, user);
}
public bool ValidateReport(Report report, User user)
{
if (!user.HasRole("Manager"))
{
throw new SecurityException("You do not have permissions to do it");
}
_service.ValidateReport(report, user);
}
public void DeleteReport(Report report, User user)
{
if (user.HasRole("Employee") || user.HasRole("Manager"))
{
throw new SecurityException("You do not have permissions to do it");
}
_service.DeleteReport(report, user);
}
}
It seems better because because role permissions checking and other logic now is splitted, doesn't it?
I also have another concern. Most likely this service will be used in ASP.NET MVC project and Microsoft proposes to use Authorize
attributes for different role permissions, like
public class ReportController : Controller
{
[HttpGet]
[Authorize(Roles="Admin")]
public void DeleteReport(int reportId)
{
}
}
If I use this approach I will duplicate role permissions logic (inside the service layer and inside the controller). What should I do? Do I need to refuse Microsoft's approach? Or do I need to remove my role permissions checking in the service layer (but in this case what do I do if my service will be used in (for example) console application)? Or is it OK to have this code duplication and have permissions checks in the service and web layers?