简体   繁体   中英

Pattern for doing authorization in repository layer of MVC application

I have a Windows authenticated MVC application with a repository layer. All interaction by the controller with the database is done through the repository. Each controller has a reference to the repository:

public class PostController : Controller
{
    private Repository db = new Repository();

    [HttpPost]
    public ActionResult DeletePost(int id)
    {
        // Authorize that the user is allowed to delete this post...

        db.DeletePost(id);
    }
}

My question is whether there is a good way to move my authorization logic into the repository layer. I'd like the Repository.DeletePost() function to refuse to delete posts that were not created by the authenticated user. The problem is that my repository does not know who the authenticated user is. The controller knows (via Controller.User ).

Passing the Controller.User into the Repository constructor doesn't work, because the Controller.User is apparently not defined at the time when the constructor is called.

How can I inform the Repository of who the authenticated user is? Would it be best to just construct the Repository within each action? Or is it a bad idea to handle it in the repository layer?

Or is it a bad idea to handle it in the repository layer?

I think the Controller is a better place for your authorization. Let the repository be a gateway to the data and the controller be a gatekeeper to your application. I'd expect to see authorization/authentication logic as early in the life-cycle as possible.

Just do something like:

db.DeletePostForUser(id, User.Identity.UserId);

Then in your repository:

public void DeletePostForUser(int id, int userId)
{
    var post = context.Posts.SingleOrDefault(m => m.PostId == id && m.User.UserId == userId)
    if (post != null)
    {
        context.Posts.Remove(post);
        context.SaveChanges();
    }
}

Good suggestions from both @BigDaddy and @ChrisPratt.

I ended up solving this by creating a base controller, similar to this answer . My base controller class looks like:

public class BaseController : Controller
{
    private ILog _log;
    private Repository _db;

    protected Repository Db
    {
        get
        {
            return _db ?? (_db = new Repository(User));
        }
    }

    protected ILog Log
    {
        get
        {
            return _log ?? (_log = LogManager.GetLogger(this.GetType()));
        }
    }
}

All of my controllers inherit from this class, and have built-in access to a lazy-loaded Repository that has a reference to the currently authenticated user.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM