我正在尝试使用委托处理程序记录到达我的端点的所有请求。由于请求和响应正文中有敏感信息,我想在日志中屏蔽它们。我尝试过使用 Destructurama.Attributed,当我记录请求的对象时它可以工作。
public class LoginRequest
{
[LogMasked(ShowFirst = 3)]
public string LoginName { get; set; }
[NotLogged]
public string Password { get; set; }
}
public class UserController : BaseApiController
{
private readonly ILogger _logger;
public UserController (ILogger logger)
{
_logger = logger;
}
[HttpPost, Route("login")]
public async Task<IHttpActionResult> Login(LoginRequest request)
{
// masking works
_logger.Information("Request: {@request}", request)
// some logic
}
}
但是,它在委托处理程序中不起作用,因为我只有请求和响应的 JSON 字符串。
在我的委托处理程序中,我使用以下方法检索请求正文:
var stream = await request.Content.ReadAsStreamAsync();
var reader = new StreamReader(stream);
reader.BaseStream.Seek(0, SeekOrigin.Begin);
var requestJsonString = reader.ReadToEnd();
有没有办法根据端点将这些JSON字符串反序列化为各自的对象?
public class GlobalLoggingHandler : DelegatingHandler
{
private readonly ILogger _logger;
public GlobalLoggingHandler(ILogger logger)
{
_logger = logger;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var endpoint = string.Join(string.Empty, request.RequestUri.Segments);
var operation = _logger.BeginOperation("HTTP {method} {endpoint}", request.Method.Method, endpoint);
try
{
var response = await base.SendAsync(request, cancellationToken);
Log(request, response);
operation.Complete();
return response;
}
catch (Exception)
{
//to-do: log error
operation.Abandon();
return new HttpResponseMessage(HttpStatusCode.InternalServerError);
}
}
private async void Log(HttpRequestMessage request, HttpResponseMessage response)
{
var requestObject = await GetHttpRequestContentAsync(request);
//this is not masking as it is JSON string
_logger.Information("Request: {@request}", requestObject);
var responseObject = await response.Content.ReadAsStringAsync();
//this is not masking as it is JSON string
_logger.Information("Response: {@response}", responseObject);
}
private async Task<string> GetHttpRequestContentAsync(HttpRequestMessage request)
{
var stream = await request.Content.ReadAsStreamAsync();
var reader = new StreamReader(stream);
reader.BaseStream.Seek(0, SeekOrigin.Begin);
return reader.ReadToEnd();
}
}
有什么办法让它适合我的情况吗?或者,我应该考虑使用 JObject 手动屏蔽我的 JSON 字符串吗?我将非常感谢任何反馈:)
我最终做的是在我的基本 api 控制器中记录请求和响应,这不是最优雅的方式,但它很简单,并且不需要在每个控制器方法中记录两行日志。
但是,我仍然非常感谢任何人可以分享一种优雅的方法。
这是我的实现:
BaseApiController.cs
public abstract class BaseApiController : ApiController
{
private readonly ILogger _logger;
protected BaseApiController(ILogger logger)
{
_logger = logger;
}
protected IHttpActionResult LogAndCreateResponseFromResult<T1, T2, T3>(Result<T1> result, T2 requestObject, T3 responseObject)
{
_logger.Information("Request: {@request}", requestObject);
_logger.Information("Response: {@response}", responseObject);
if (result.IsFailure)
{
ModelState.AddModelError(result.Error.Code, result.Error.Message);
return BadRequest(ModelState);
}
return Ok(responseObject);
}
}
用户控制器.cs
public class UserController : BaseApiController
{
public UserController (ILogger logger) : base(logger)
{
}
[HttpPost, Route("login")]
public async Task<IHttpActionResult> Login(LoginRequest request)
{
// some logic
var result = await someLogicAsync();
return LogAndCreateResponseFromResult(result, request, response);
}
}