2014-09-05 35 views
0

我正在使用UserProfile编辑页面,其中只能编辑UserProfile模型的字段子集。许多字段只能对具有特殊角色的用户进行编辑,并且字段UserName当然是不可编辑且隐藏的。如何在回发后维护模型值而不暴露它们

现在我想包括hiddenfields为所有不被用户编辑的字段,以及装饰我的模式是这样的:代码

[Table("UserProfile")] 
public partial class UserProfile 
{ 
    public UserProfile() 
    { 
     webpages_Roles = new HashSet<Role>(); 
    } 

    [Key] 
    public int UserId { get; set; } 

    [Required] 
    [StringLength(56)] 
    [Display(Name="Email")] 
    [Editable(false)] // is this the way to go? 
    public string UserName { get; set; } 

    [Required] 
    [Display(Name = "First name")] 
    [StringLength(256)] 
    public string FirstName { get; set; } 

    [Editable(false)] // is this the way to go? 
    public bool SomeSetting { get; set; } 

    // ... more properties are unimportant for this example 
} 

其他相关位:

// 
    // GET: /Account/Profile 

    public ActionResult UserProfile() 
    { 
     var userProfile = db.UserProfiles.Find(WebSecurity.CurrentUserId); 

     return View(userProfile); 
    } 

    // 
    // POST: /Account/Profile 

    [HttpPost] 
    [AllowAnonymous] 
    [ValidateAntiForgeryToken] 
    public ActionResult UserProfile(UserProfile model) 
    { 
     // if I dont include UserName, validation will fail since it 
     // is now null and the field is [Required] 
     if (ModelState.IsValid) 
     { 
      // if I dont include hidden fields, UserId, UserName 
      // and SomeSetting will be null here 
      db.Entry(model).State = EntityState.Modified; 
      db.SaveChanges(); 
     } 

     return View(model); 
    } 

相关视图代码:

@Html.HiddenFor(m => m.UserId) 
@Html.HiddenFor(m => m.UserName) 
@Html.HiddenFor(m => m.SomeSetting) 

不过,我很担心这些暴露通过隐藏输入字段。不管聪明还是恶意用户都无法编辑它们?我明白,我必须包括他们,否则在回传后属性将为null。有人能够启发我吗?

+0

可以使用_viewmodel_,并与您_model_ – 2014-09-05 15:19:43

+0

'地图也不会聪明或恶意用户能够反正编辑'是的,你应该验证在回发或Si的作用? milar。你可以使用'ViewModel'并根据​​角色设置单独的属性,而不是整个实体。 – Jonesopolis 2014-09-05 15:20:17

+0

@Jonesy听起来不错。 ViewModel和Model之间的映射最简单的方法是什么? AutoMapper?还是有更简单的方法? – Korijn 2014-09-05 16:15:25

回答

0

如果您担心安全问题,则应在回发后从数据库中检索实体,然后从提交的模型中更新可编辑属性。要检索您的模型,我认为可以将UserId保留为隐藏字段:@Html.HiddenFor(m => m.UserId)

我希望这个答案有帮助。

+0

我认为使用ViewModel是一个更好的主意(请参阅问题的评论)。此外,我可以使用WebSecurity.CurrentUserId,这样我就不必公开UserId。 – Korijn 2014-09-05 16:16:56

1

你可以做这样的事情产生的哈希作为模型中的一个属性,它是一个连接字符串的所有值的哈希 - 例如:

添加一个新的属性到你的视图模型(可以使用[NotMapped]注释如果这也是你的数据库对象):

public string SecurityHash {get;set;} 

创建一个助手简单的散列函数(或控制器):

public string CalculateMD5Hash(string input) 
{ 
    // step 1, calculate MD5 hash from input 
    MD5 md5 = System.Security.Cryptography.MD5.Create(); 
    byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input); 
    byte[] hash = md5.ComputeHash(inputBytes); 

    // step 2, convert byte array to hex string 
    StringBuilder sb = new StringBuilder(); 
    for (int i = 0; i < hash.Length; i++) 
    { 
     sb.Append(hash[i].ToString("X2")); 
    } 
    return sb.ToString(); 
} 

现在设置散列值在你的控制器:

// 
// GET: /Account/Profile 

public ActionResult UserProfile() 
{ 
    var userProfile = db.UserProfiles.Find(WebSecurity.CurrentUserId); 
    userProfile.SecurityHash = MyHashHelper.CalculateMD5Hash(userProfile.UserID + userProfile.UserName + userProfile.SomeSetting) 
    return View(userProfile); 
} 

那么在你看来,你的坚持散列值:

@Html.HiddenFor(m => m.UserId) 
@Html.HiddenFor(m => m.UserName) 
@Html.HiddenFor(m => m.SomeSetting) 
@Html.HiddenFor(m => m.SecurityHash) 

最后,您可以检查,如果你的价值观已被篡改,重新购买后门柱散列:

// 
// POST: /Account/Profile 

[HttpPost] 
[AllowAnonymous] 
[ValidateAntiForgeryToken] 
public ActionResult UserProfile(UserProfile model) 
{ 
    string hashCheckVal = MyHashHelper.CalculateMD5Hash(model.UserID + model.UserName + model.SomeSetting) 
    if(string.Compare(hashCheckVal, model.SecurityHash) != 0) 
    { 
     throw new Exception("tampered with!"); 
    } 

    // if I dont include UserName, validation will fail since it 
    // is now null and the field is [Required] 
    if (ModelState.IsValid) 
    { 
     // if I dont include hidden fields, UserId, UserName 
     // and SomeSetting will be null here 
     db.Entry(model).State = EntityState.Modified; 
     db.SaveChanges(); 
    } 

    return View(model); 
}