0

寻找一种干净、安全的方法,只允许某些用户(按角色)编辑视图中的某些字段。这里的关键词是edit,因为仅显示/隐藏视图的一部分(按钮、链接等)是一回事,但在将“受保护”字段发布回控制器时如何处理它们是另一回事。

例如,我可以这样做:

查看模型

public class CustomerEditViewModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    // Other properties...

    public string Email { get; set; }
    public string Phone { get; set; }

    public bool CanEditContactInfo { get; set; } 
}

看法

@Html.EditorFor(m => m.FirstName)
@Html.EditorFor(m => m.LastName)

@if (Model.CanEditContactInfo)
{
    @Html.EditorFor(m => m.Email)
    @Html.EditorFor(m => m.Phone)
}

控制器

[HttpGet]
public ActionResult Edit(int id)
{
    var customer = _customerService.GetCustomerById(id);
    var model = Mapper.Map<CustomerEditViewModel>(customer);
    model.CanEditContactInfo = User.IsInRole("Admin");
    return View(model);
}

[HttpPost]
public ActionResult Edit(CustomerEditViewModel model)
{
    var customer = _customerRepo.GetCustomerById(model.Id);
    Mapper.Map(model, customer);
    _customerService.UpdateCustomer(customer);
    // return to Index view
}

但问题是,当非管理员用户编辑客户时,这些字段Email永远Phone不会在视图上呈现,因此当表单回发到控制器时它们将为 NULL,并且会进一步覆盖实际值带有 NULL 的数据库。

我可以这样解决这个问题:

@Html.EditorFor(m => m.FirstName)
@Html.EditorFor(m => m.LastName)

@if (Model.CanEditContactInfo)
{
    @Html.EditorFor(m => m.Email)
    @Html.EditorFor(m => m.Phone)
}
else
{
    @Html.HiddenFor(m => m.Email)
    @Html.HiddenFor(m => m.Phone)
}

即使非管理员用户正在编辑记录,这也会保留原始的电子邮件/电话值,但问题是电子邮件/电话字段在呈现的 HTML 中作为隐藏字段可用,并且可以很容易地被浏览器工具操作之前发回。

我确实有一些想法,但它们变得一团糟。所以我想知道对于这样的事情可能已经有哪些成功的方法。

4

1 回答 1

2

The first rule of thumb in secure coding is that the client input cannot be trusted, which means you MUST apply your checks and validations in the server side. In your case, the HttpPost controller action should check the user role again. If user is not authorized to update all properties, then you could:

1- Load the original data again and overwrite the properties that can be updated with user input and then save this updated copy:

[HttpPost]
public ActionResult Edit(CustomerEditViewModel model)
{
    var customer = _customerRepo.GetCustomerById(model.Id);
    // Check the current user role.    
    If (!User.IsInRole("Admin"))
    {
       customer.FirstName = model.FirstName;
       customer.LastName = model.LastName;
    }
    else
    {
       Mapper.Map(model, customer);
    }
    _customerService.UpdateCustomer(customer);
    // return to Index view
}

2- Create another mapping method that ignores the properties that can not be updated from user input and call the right mapper based on the user permission

public static Customer ToEntity(this CustomerEditViewModel model, Customer destination)
{
    return Mapper.CreateMap<CustomerEditViewModel, Customer>()
                 .ForMember(dest => dest.Email, opt => opt.Ignore()
                 .ForMember(dest => dest.Phone, opt => opt.Ignore()
                );
} 
于 2018-01-10T18:10:42.987 回答