ASP.NET Web API中简单属性的自定义类型转换器



在ASP.NET Web API项目中,我希望加密所有响应中的所有实体ID,并解密所有请求中的加密值。

(注意:我知道如何加密/解密数据,这不是我的问题。)

我认为如果我只在响应/请求中装饰需要加密/解密的属性,并使用自定义属性,那就太好了。

这就是我喜欢它的工作方式:

public class Person
{
  [EncryptDecrypt]
  public int PersonID {get; set;}
  public string Name {get; set;}
  public IEnumerable<Order> Orders {get; set;}
}
public class Order 
{
    [EncryptDecrypt]
    public long OrderID {get; set;}
    public string Title {get; set;}
    public float Price {get; set;}
}

然后在Web API方法:

// GET: api/persons/xhj$j78dPs (xhj$j78dPs is an encrypted PersonID)    
public Person Get([EncryptDecrypt]int personId)
{
    // Now, I expect personId to be a normal ID, like: 187356
    Person person = _repository.GetPerson(personId);
    return person;
}

上述Web API的期望响应是:

{
   "personId": "xhj$j78dPs",
   "name": "Joe Williams",
   "orders": [
      {
         "orderId": "a#jd75mlzed0ihd",
         "title": "Buying a new item",
         "price": 19.99
      }
    ]
 }

这是另一个例子,这次是PUT谓词的Web API

/* PUT Request body: */
{
   "orderId": "a#jd75mlzed0ihd",
   "title": "Buying a new item - edited",
   "price": 13.00
}

相关Web API方法:

// PUT: api/persons/xhj$j78dPs/orders/ (xhj$j78dPs is an encrypted PersonID)
public void Put([EncryptDecrypt]int personId, Order editedOrder)
{
    // I expect personId to be a normal ID, like: 187356
    // I expect editedOrder.OrderID to be a normal ID, like: 10000089765
    _repository.UpdateOrder(personId, editedOrder);
}

如何开发[EncryptDecrypt]属性?

[EncryptDecrypt]实际上应该是JsonConverter属性吗?或者我应该开发一个自定义的介质格式化程序或模型活页夹或值提供程序或参数活页夹吗?我很困惑。

如何开发[EncryptDecrypt]属性?

[EncryptDecrypt]实际上应该是JsonConverter属性吗?或者我应该开发一个自定义的介质格式化程序或模型活页夹或值提供程序或参数活页夹吗?我很困惑。

你需要两者兼而有之;用于对JSON数据进行(反)序列化的自定义JsonConverter和用于将(加密的int/long)值绑定到端点参数的自定义ModelBinder

试试这样的东西:

public class EncryptDecrypt : JsonConverter, IModelBinder 
{    
  public override bool CanConvert(Type objectType)
  {
    return typeof(int).IsAssignableFrom(objectType) || 
           typeof(long).IsAssignableFrom(objectType);
  }
  public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
  {
    // Deserialize the provided value as string
    // and decrypt it to its exprected int/long type 
    var value = serializer.Deserialize<string>(reader);
    return Decrypt(value, objectType);
  }
  public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
  {
    // obviously Encrypt() should convert the int/ long value 
    // to its encrypted string representation.
    var encrypted = Encrypt(value);
    writer.WriteValue(encrypted);
  }
  public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
  {
    if (!CanConvert(bindingContext.ModelType)) return false;
    var val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
    if (val == null) return false;
    // bindingContext.ModelType should tell us whether the decrypted value 
    // is expected as an int/ long.
    var decrypted = Decrypt(val.RawValue as string, bindingContext.ModelType);
    if (decrypted != null)
    {
      bindingContext.Model = decrypted;
      return true;
    }
    bindingContext.ModelState.AddModelError(bindingContext.ModelName, "Cannot convert value");
    return false;
  }
}

然后你可以这样装饰模型:

public class Person
{
  [JsonConverter(typeof(EncryptDecrypt))]
  public int PersonID { get; set; }
  public string Name { get; set; }
  public IEnumerable<Order> Orders { get; set; }
}
public class Order
{
  [JsonConverter(typeof(EncryptDecrypt))]    
  public long OrderID { get; set; }
  public string Title { get; set; }
  public float Price { get; set; }
}

至于Web API方法,您需要将其装饰为:

public IHttpActionResult Get([ModelBinder(typeof(EncryptDecrypt))] int personId)
{
  // Now, I expect personId to be a normal ID, like: 187356
  Person person = _repository.GetPerson(personId);
  return Json(person);
}
public void Put([ModelBinder(typeof(EncryptDecrypt))] int personId, Order editedOrder)
{
  // I expect personId to be a normal ID, like: 187356
  // I expect editedOrder.OrderID to be a normal ID, like: 10000089765
  _repository.UpdateOrder(personId, editedOrder);
}

相关内容

  • 没有找到相关文章

最新更新