简体   繁体   English

在MVC应用程序的存储库层中进行授权的模式

[英]Pattern for doing authorization in repository layer of MVC application

I have a Windows authenticated MVC application with a repository layer. 我有一个带有存储库层的Windows身份验证的MVC应用程序。 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. 我希望Repository.DeletePost()函数拒绝删除未经过身份验证的用户创建的帖子。 The problem is that my repository does not know who the authenticated user is. 问题是我的存储库不知道经过身份验证的用户是谁。 The controller knows (via Controller.User ). 控制器知道(通过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. Controller.User传递到Repository构造函数不起作用,因为在调用构造函数时, Controller.User显然没有定义。

How can I inform the Repository of who the authenticated user is? 如何通知Repository谁是经过身份验证的用户? Would it be best to just construct the Repository within each action? 在每个动作中构建Repository是否最好? 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. 来自@BigDaddy和@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. 我的所有控制器都继承自此类,并且具有对延迟加载的Repository内置访问权,该Repository具有对当前经过身份验证的用户的引用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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