Alex Rivera | Logout

Access Control in ASP.NET MVC depending on input parameters / service layer?

Asked 2009-08-26T14:54:01.773
41

Preamble: this is a bit of a philosophical question. I'm looking more for the "right" way to do this rather than "a" way to do this.

Let's imagine I have some products, and an ASP.NET MVC application performing CRUD on those products:-

mysite.example/products/1
mysite.example/products/1/edit

I'm using the repository pattern, so it doesn't matter where these products come from:-

public interface IProductRepository
{
  IEnumberable<Product> GetProducts();
  ....
}

Also my Repository describes a list of Users, and which products they are managers for (many-many between Users and Products). Elsewhere in the application, a Super-Admin is performing CRUD on Users and managing the relationship between Users and the Products they are permitted to manage.

Anyone is allowed to view any product, but only users who are designated as "admins" for a particular product are allowed to invoke e.g. the Edit action.

How should I go about implementing that in ASP.NET MVC? Unless I've missed something, I can't use the built-in ASP.NET Authorize attribute as first I'd need a different role for every product, and second I won't know which role to check for until I've retrieved my Product from the Repository.

Obviously you can generalise from this scenario to most content-management scenarios - e.g. Users are only allowed to edit their own Forum Posts. StackOverflow users are only allowed to edit their own questions - unless they've got 2000 or more rep...

The simplest solution, as an example, would be something like:-

public class ProductsController
{
  public ActionResult Edit(int id)
  {
    Product p = ProductRepository.GetProductById(id);
    User u = UserService.GetUser(); // Gets the currently logged in user
    if (ProductAdminService.UserIsAdminForProduct(u, p))
    {
      return View(p);
    }
    else
    {
      return RedirectTo
Edit
Report

1 Answer

1

I tend to think that authorization is part of your business logic (or at least outside of your controller logic anyway). I agree with kevingessner above, in that the authorization check should be part of the call to fetch the item. In his OnException method, you could show the login page (or whatever you have configured in the web.config) by something like this:

if (...)
{
    Response.StatusCode = 401;
    Response.StatusDescription = "Unauthorized";
    HttpContext.Response.End();
}

And instead of making UserRepository.GetUserSomehowFromTheRequest() calls in all the action methods, I would do this once (in an override of the Controller.OnAuthorization method for example), then stick that data somewhere in your controller base class for later use (e.g. a property).

answered 2009-08-27T03:00:18.180

Your Answer