使用 Serilog 和 Destructurama.Attributed 屏蔽委托处理程序中的日志

问题描述 投票:0回答:1

我正在尝试使用委托处理程序记录到达我的端点的所有请求。由于请求和响应正文中有敏感信息,我想在日志中屏蔽它们。我尝试过使用 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 字符串吗?我将非常感谢任何反馈:)

logging serilog webapi masking .net-4.8
1个回答
0
投票

我最终做的是在我的基本 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);
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.