I'm building the 2nd iteration of a web-based CRM+CMS for a franchise service business in ASP.NET MVC 2. I need to control access to each franchise's services based on the roles a user is assigned for that franchise.
4 examples:
Receptionist should be able to book service jobs in for her "Atlantic Seaboard" franchise, but not do any reporting.
Technician should be able to alter service jobs, but not modify invoices.
Managers should be able to apply discount to invoices for jobs within their stores.
Owner should be able to pull reports for any franchises he owns.
Where should franchise-level access control fit in between the Data - Services - Web layer?
If it belongs in my Controllers, how should I best implement it?
Partial Schema
Roles class
int ID { get; set; } // primary key for Role
string Name { get; set; }
Partial Franchises class
short ID { get; set; } // primary key for Franchise
string Slug { get; set; } // unique key for URL access, eg /{franchise}/{job}
string Name { get; set; }
UserRoles mapping
short FranchiseID; // related to franchises table
Guid UserID; // related to Users table
int RoleID; // related to Roles table
DateTime ValidFrom;
DateTime ValidUntil;
Background
I built the previous CRM in classic ASP and it runs the business well, but it's time for an upgrade to speed up workflow and leave less room for error. For the sake of proper testing and better separation between data and presentation, I decided to implement the repository pattern as seen in Rob Conery's MVC Storefront series.
Controller Implementation
Access Control with [Authorize] attribute
If there was just one franchise involved, I could simply limit access to a controller action like so:
[Authorize(Roles="Receptionist, Technician, Manager, Owner")]
public ActionResult CreateJob(Job job)
{
...
}
And since franchises don't just pop up over night, perhaps this is a strong case to use the new Areas feature in ASP.NET MVC 2? Or would this lead to duplicate Views?
Controllers, URL Routing & Areas
Assuming Areas aren't used, what would be the best way to determine which franchise's data is being accessed? I thought of this:
{franchise}/{controller}/{action}/{id}
or is it better to determine a job's franchise in a Details(...) action and limit a user's action with [Authorize]:
{job}/{id}/{action}/{subaction}
{invoice}/{id}/{action}/{subaction}
which makes more sense if any user could potentially have access to more than one franchise without cluttering the URL with a {franchise} parameter.
Any input is appreciated.