(我知道這個問題是非常相似的How to whitelist/blacklist child object fields in the ModelBinder/UpdateModel method?但我的情況是不同的,有可能是現在可以更好的解決辦法,這不是呢。)選擇性白名單模型字段到綁定
我們公司銷售基於web該軟件可以由最終用戶極爲配置。這種靈活性的性質意味着我們必須在編譯時通常在運行時間上執行一些操作。
關於誰讀取或讀取/寫入大部分內容都有一些相當複雜的規則。
舉例來說,採取這種模式,我們想創造:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace j6.Business.Site.Models
{
public class ModelBindModel
{
[Required]
[Whitelist(ReadAccess = true, WriteAccess = true)]
public string FirstName { get; set; }
[Whitelist(ReadAccess = true, WriteAccess = true)]
public string MiddleName { get; set; }
[Required]
[Whitelist(ReadAccess = true, WriteAccess = true)]
public string LastName { get; set; }
[Required]
[Whitelist(ReadAccess = User.CanReadSalary, WriteAccess = User.CanWriteSalary)]
public string Salary { get; set; }
[Required]
[Whitelist(ReadAccess = User.CanReadSsn, WriteAccess = User.CanWriteSsn)]
public string Ssn { get; set; }
[Required]
public string SirNotAppearingOnThisPage { get; set; }
}
}
在控制器,它並不難「解除綁定」手工的東西。
var resetValue = null;
modelState.Remove(field);
pi = model.GetType().GetProperty(field);
if (pi == null)
{
throw new Exception("An exception occured in ModelHelper.RemoveUnwanted. Field " +
field +
" does not exist in the model " + model.GetType().FullName);
}
// Set the default value.
pi.SetValue(model, resetValue, null);
使用HTML幫助程序,我可以輕鬆訪問模型元數據並抑制呈現用戶無權訪問的任何字段。
踢球者:我不知道如何訪問模型元數據本身的任何地方,以防止過度發佈。
請注意,使用[綁定(包括...)]不是一個功能性解決方案,至少不是沒有額外的支持。要包含的屬性是運行時(不是編譯時間)相關的,排除屬性而不是將其從驗證中移除。
ViewData.Model
是null
ViewData.ModelMetaData
是null
[AllowAnonymous]
[HttpPost]
// [Bind(Exclude = "Dummy1" + ",Dummy2")]
public ViewResult Index(ModelBindModel dto)
{
zzz.ModelHelper.RemoveUnwanted(ModelState, dto, new string[] {"Salary", "Ssn"});
ViewBag.Method = "Post";
if (!ModelState.IsValid)
{
return View(dto);
}
return View(dto);
}
如何從控制器訪問模型元數據有什麼建議?或者在運行時將白名單列入白名單的更好方法?
更新:
我借了頁面從這個相當優秀的資源:
http://www.dotnetcurry.com/ShowArticle.aspx?ID=687
與模型,看起來像這樣:
[Required]
[WhiteList(ReadAccessRule = "Nope", WriteAccessRule = "Nope")]
public string FirstName { get; set; }
[Required]
[WhiteList(ReadAccessRule = "Database.CanRead.Key", WriteAccessRule = "Database.CanWrite.Key")]
public string LastName { get; set; }
類:
public class WhiteList : Attribute
{
public string ReadAccessRule { get; set; }
public string WriteAccessRule { get; set; }
public Dictionary<string, object> OptionalAttributes()
{
var options = new Dictionary<string, object>();
var canRead = false;
if (ReadAccessRule != "")
{
options.Add("readaccessrule", ReadAccessRule);
}
if (WriteAccessRule != "")
{
options.Add("writeaccessrule", WriteAccessRule);
}
if (ReadAccessRule == "Database.CanRead.Key")
{
canRead = true;
}
options.Add("canread", canRead);
options.Add("always", "be there");
return options;
}
}
而且這些行添加到鏈接中提到的MetadataProvider類:
var whiteListValues = attributes.OfType<WhiteList>().FirstOrDefault();
if (whiteListValues != null)
{
metadata.AdditionalValues.Add("WhiteList", whiteListValues.OptionalAttributes());
}
最後,該系統的心臟:
public static void DemandFieldAuthorization<T>(ModelStateDictionary modelState, T model)
{
var metaData = ModelMetadataProviders
.Current
.GetMetadataForType(null, model.GetType());
var props = model.GetType().GetProperties();
foreach (var p in metaData.Properties)
{
if (p.AdditionalValues.ContainsKey("WhiteList"))
{
var whiteListDictionary = (Dictionary<string, object>) p.AdditionalValues["WhiteList"];
var key = "canread";
if (whiteListDictionary.ContainsKey(key))
{
var value = (bool) whiteListDictionary[key];
if (!value)
{
RemoveUnwanted(modelState, model, p.PropertyName);
}
}
}
}
}
+1 - 優秀的問題。如果沒有其他解決方案可用,我想你可以評估用戶和模型,作爲POST/PUT中第一步的任何不匹配。它看起來像你的模型包含足夠的元數據來做出決定。當然,該評估邏輯將駐留在助手類中,因此它只會爲每個操作方法添加1-2行,例如'ModelHelper.DemandFieldAuthorization(model,user)' – 2013-04-10 21:27:02
@TimMedora - 您可否詳細說明「評估用戶和模型是POST/PUT的第一步」?我不太確定你的意思。 – 2013-04-10 21:33:25
當然,給我一分鐘,我會把它寫出來作爲答案。 – 2013-04-10 21:34:30