gpt4 book ai didi

asp.net-mvc-4 - 使用 MVC4 ApiController 时如何清理 JSON 输入参数?

转载 作者:行者123 更新时间:2023-12-02 06:19:51 24 4
gpt4 key购买 nike

我构建了一个基于 AntiXSS 的 HTML 清理程序,通过覆盖默认模型绑定(bind)器来自动清理用户输入字符串,该模型在标准发布请求上运行良好。然而,当使用新的 ApiController 时,默认模型绑定(bind)器永远不会被调用,我认为这是因为这个新的 MVC Controller 使用 JSON 格式化程序来绑定(bind)请求正文中的输入数据。

那么如何扩展格式化程序,以便我可以在字符串属性被 JSON 绑定(bind)后修改它们呢?我宁愿不必在 Controller 级别实现这一点,并且应该有一种方法可以在它到达 Controller 之前完成它。

最佳答案

我通过创建修改后的 Json 格式化程序解决了我的问题,但是大多数有关如何执行此操作的文档都是基于 .Net 4.0 的预发布代码。

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Formatting;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Reflection;
using System.Threading.Tasks;
using System.Web;
using System.Web.Script.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

public class JsonNetFormatterAntiXss : JsonMediaTypeFormatter
{
public override bool CanReadType(Type type)
{
return base.CanReadType(type);
}
public override bool CanWriteType(Type type)
{
return base.CanWriteType(type);
}

public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
{
HttpContentHeaders contentHeaders = content == null ? null : content.Headers;
// If content length is 0 then return default value for this type
if (contentHeaders != null && contentHeaders.ContentLength == 0)
{
return Task.FromResult(MediaTypeFormatter.GetDefaultValueForType(type));
}

// Get the character encoding for the content
Encoding effectiveEncoding = SelectCharacterEncoding(contentHeaders);

try
{
using (JsonTextReader jsonTextReader = new JsonTextReader(new StreamReader(readStream, effectiveEncoding)) { CloseInput = false, MaxDepth = _maxDepth })
{
JsonSerializer jsonSerializer = JsonSerializer.Create(_jsonSerializerSettings);
if (formatterLogger != null)
{
// Error must always be marked as handled
// Failure to do so can cause the exception to be rethrown at every recursive level and overflow the stack for x64 CLR processes
jsonSerializer.Error += (sender, e) =>
{
Exception exception = e.ErrorContext.Error;
formatterLogger.LogError(e.ErrorContext.Path, exception);
e.ErrorContext.Handled = true;
};
}

return Task.FromResult(DeserializeJsonString(jsonTextReader, jsonSerializer, type));
}

}
catch (Exception e)
{
if (formatterLogger == null)
{
throw;
}
formatterLogger.LogError(String.Empty, e);
return Task.FromResult(MediaTypeFormatter.GetDefaultValueForType(type));
}
}

private object DeserializeJsonString(JsonTextReader jsonTextReader, JsonSerializer jsonSerializer, Type type)
{
object data = jsonSerializer.Deserialize(jsonTextReader, type);

// sanitize strings if we are told to do so
if(_antiXssOptions != AntiXssOption.None)
data = CleanAntiXssStrings(data); // call your custom XSS cleaner

return data;
}

/// <summary>
/// Clean all strings using internal AntiXss sanitize operation
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
private object CleanAntiXssStrings(object data)
{
PropertyInfo[] properties = data.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
Type ptype = property.PropertyType;
if (ptype == typeof(string) && ptype != null)
{
// sanitize the value using the preferences set
property.SetValue(data, DO_MY_SANITIZE(property.GetValue(data).ToString()));
}
}
return data;
}

public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, System.Net.TransportContext transportContext)
{
return base.WriteToStreamAsync(type, value, writeStream, content, transportContext);
}

private DataContractJsonSerializer GetDataContractSerializer(Type type)
{
Contract.Assert(type != null, "Type cannot be null");
DataContractJsonSerializer serializer = _dataContractSerializerCache.GetOrAdd(type, (t) => CreateDataContractSerializer(type, throwOnError: true));

if (serializer == null)
{
// A null serializer means the type cannot be serialized
throw new InvalidOperationException(String.Format("Cannot serialize '{0}'", type.Name));
}

return serializer;
}

private static DataContractJsonSerializer CreateDataContractSerializer(Type type, bool throwOnError)
{
if (type == null)
{
throw new ArgumentNullException("type");
}

DataContractJsonSerializer serializer = null;
Exception exception = null;

try
{
// Verify that type is a valid data contract by forcing the serializer to try to create a data contract
XsdDataContractExporter xsdDataContractExporter = new XsdDataContractExporter();
xsdDataContractExporter.GetRootElementName(type);
serializer = new DataContractJsonSerializer(type);
}
catch (InvalidDataContractException invalidDataContractException)
{
exception = invalidDataContractException;
}

if (exception != null)
{
if (throwOnError)
{
throw new InvalidOperationException(String.Format("Can not serialize type '{0}'.", type.Name), exception);
}
}

return serializer;
}

}

我将此代码基于 Json.NET implementation JsonMediaTypeFormatter 以及这个 article 。至于我的 AntiXSS 实现,我没有费心发布它,它结合使用了 AntiXSS 4.2.1 和自定义解析,因为该库的保护过度了。

关于asp.net-mvc-4 - 使用 MVC4 ApiController 时如何清理 JSON 输入参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19017867/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com