C# ASP.NET MVC属性,仅允许用户编辑自己的内容

C# ASP.NET MVC属性,仅允许用户编辑自己的内容,c#,.net,asp.net-mvc,security,authentication,C#,.net,Asp.net Mvc,Security,Authentication,我有一个名为Edit的控制器方法,用户可以像这样编辑他们创建的数据 public ActionResult Edit(int id) { Submission submission = unit.SubmissionRepository.GetByID(id); User user = unit.UserRepository.GetByUsername(User.Identity.Name); //Make sure the submission belongs to

我有一个名为
Edit
的控制器方法,用户可以像这样编辑他们创建的数据

public ActionResult Edit(int id)
{
    Submission submission = unit.SubmissionRepository.GetByID(id);
    User user = unit.UserRepository.GetByUsername(User.Identity.Name);

    //Make sure the submission belongs to the user
    if (submission.UserID != user.UserID)
    {
        throw new SecurityException("Unauthorized access!");
    }

    //Carry out method
}

此方法工作正常,但将每个控制器编辑方法都放进去有点混乱。每个表都有一个
用户ID
,因此我想知道是否有更简单的方法可以通过
[Authorize]
属性或其他机制来自动执行此操作,从而使代码更干净。

是的,您可以通过自定义Authorize属性来实现这一点:

public class MyAuthorizeAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var authorized = base.AuthorizeCore(httpContext);
        if (!authorized)
        {
            return false;
        }

        var rd = httpContext.Request.RequestContext.RouteData;

        var id = rd.Values["id"];
        var userName = httpContext.User.Identity.Name;

        Submission submission = unit.SubmissionRepository.GetByID(id);
        User user = unit.UserRepository.GetByUsername(userName);

        return submission.UserID == user.UserID;
    }
}
然后:

[MyAuthorize]
public ActionResult Edit(int id)
{
    // Carry out method
}
[MyAuthorize]
public ActionResult Edit(Submission model)
{
    // Carry out method
}
假设您需要将这个提交实例作为操作参数输入到自定义属性中,以避免再次命中数据库,您可以执行以下操作:

public class MyAuthorizeAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var authorized = base.AuthorizeCore(httpContext);
        if (!authorized)
        {
            return false;
        }

        var rd = httpContext.Request.RequestContext.RouteData;

        var id = rd.Values["id"];
        var userName = httpContext.User.Identity.Name;

        Submission submission = unit.SubmissionRepository.GetByID(id);
        User user = unit.UserRepository.GetByUsername(userName);

        rd.Values["model"] = submission;

        return submission.UserID == user.UserID;
    }
}
然后:

[MyAuthorize]
public ActionResult Edit(int id)
{
    // Carry out method
}
[MyAuthorize]
public ActionResult Edit(Submission model)
{
    // Carry out method
}

我建议阅读
authorized属性
(请参阅)。还有,你看过这篇文章吗?它讨论了如何重写内部的身份验证属性以及如何使用IPrincipal和IIdentity。

我建议您从操作/控制器中提取逻辑,并构建一个域类来处理该逻辑

操作方法实际上应该只处理从视图获取数据和向视图发送数据。您可以创建一些足够通用的东西来处理您的需求,但也将遵循单一责任原则

public class AuthorizedToEdit 
{
     protected override bool AuthorizeCore(string user, int itemId)
     {
         var userName = httpContext.User.Identity.Name;

         var authUsers = SubmissionRepository.GetAuthoriedUsers(itemId);

         return authUsers.Contains(user);
     }
}
这还允许您以后灵活地允许管理员用户之类的用户

@if (Request.IsAuthenticated && User.IsInRole("Student"))
    {
    @Html.ActionLink("Edit", "Edit", new { id = item.StdID })
    }
在我的例子中,loggedIn用户是一名学生。所以我说,如果登录请求经过身份验证,并且他的角色是学生,那么让他可以访问编辑链接

下面允许您让普通用户或管理员也执行编辑

@if(Request.IsAuthenticated && User.IsInRole("Student") || 
User.IsInRole("Administrator"))
{
 @Html.ActionLink("Edit", "Edit", new { id = item.StdID })
}

非常感谢。我要让它更通用。与此类似,我们实现了一个名为IUserOwnable的接口,该接口具有用户ID。然后将存储库传递到属性中,在该属性中获取一个IUSerowTable,并将该用户的用户ID与IUSerowTable的用户ID进行比较。当然,这可以根据您的特定需求进行通用化。很好的方法。我想现在它会有一个内置的属性,你如何缓存它,这样它就不需要在每次有授权人属性的时候都检查数据库了@DarinDimitrov@DarinDimitrov在基于JWT令牌的身份验证的web API中,实现.net核心的最佳方法是什么?