C# .net 核心,没有敏感信息的日志请求

  • 本文关键字:信息 日志 请求 net 核心 c#
  • 更新时间 :
  • 英文 :


使用 .net core 2.1 C# 7.1.

我有一个 API REST 服务器。

我有以下课程:

public class ActionTimingAttribute : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// do something before the action executes
DateTime execStart = DateTime.UtcNow;
var request = context.HttpContext.Request;
string payload = ""; // HERE I NEED THE PAYLOAD WITHOUT SENSITIVE DATA
//doing funky stuff
await next();
DateTime execEnd = DateTime.UtcNow;
double elapsed = (execEnd - execStart).TotalMilliseconds;
Log(payload, elapsed);
}
}

现在,我可以和new StreamReader(request.Body)一起拿payload,其余的。 但是,例如,如果我有一个密码字段,我不希望payload具有此值。例如,我想将值更改为"#####"。

我对很多请求和不同的要求都有这个。 对于每个POST请求,我都有一个代表收到的 json 的类......

显然我不关心HttpGet。

我的服务器中的一个方法看起来像这样(一个仅用于登录的示例..)

[HttpPost, Route("Auth/Login")]
public async Task<Responses.Login> Login (Requests.Login request)

我假设我需要某种属性,所以它看起来像:

public class Login
{
public string Email {set;get;}
[SensitiveData]
public string Password {set;get;}
}

但是在这里,我无法在我有有效负载的地方进行最终组合,我想省略任何敏感数据。

如果我有请求模型,我可以查看它的字段并检查它们是否敏感,如果是,则更改模型中的值(假设它不会损害控制器实际接收的模型)。

谢谢。

下面是使用自定义 NewtonSoft 序列化的解决方案。 反射代码可能有一些改进的余地。

public class SensitiveDataAttribute: Attribute
{
}
public sealed class SensitiveDataJsonConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
foreach (PropertyInfo prop in value.GetType().GetProperties())
{
object[] attrs = prop.GetCustomAttributes(true);
if (attrs.Any(x => x is SensitiveDataAttribute))
prop.SetValue(value, "#####");
}
var t = JToken.FromObject(value);
if (t.Type != JTokenType.Object)
{
t.WriteTo(writer);
}
else
{
JObject o = (JObject)t;
o.WriteTo(writer);
}
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
}
public override bool CanRead => false;
public override bool CanConvert(Type objectType)
{
return true;
}
}

这就是它的使用方式。

public class MyObject
{
[SensitiveData]
public string Password { get; set; }
public string UserName { get; set; }
}

ActionTimingAttribute : IAsyncActionFilter

private static readonly SensitiveDataJsonConverter SensitiveDataConverter = new SensitiveDataJsonConverter();
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
string safePayload;
if (context.ActionArguments.Count == 1)
{
var safeObject = context.ActionArguments[context.ActionArguments.Keys.ElementAt(0)];
safePayload = JsonConvert.SerializeObject(safeObject, Formatting.None, SensitiveDataConverter);
}
else
safePayload = request.StoreAndGetPayload();

// the rest..
}

要处理不更改原始文件,您可以像下面描述的那样进行克隆: 深度克隆对象

public static class ObjectCopier
{
public static T CloneJson<T>(this T source)
{
// Don't serialize a null object, simply return the default for that object
if (Object.ReferenceEquals(source, null))
{
return default(T);
}
// initialize inner objects individually
// for example in default constructor some list property initialized with some values,
// but in 'source' these items are cleaned -
// without ObjectCreationHandling.Replace default constructor values will be added to result
var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
}
}

然后,您的使用情况将如下所示:

safePayload = JsonConvert.SerializeObject(safeObject.CloneJson(), Formatting.None, SensitiveDataConverter);

最新更新