关于 Middleware 启用 EnableBuffering 多次读取 Net Core 自定义 Middleware 加密解密

延续上一篇 Net Core 自定义 Middleware 加密解密 做重构,以及BUG修复

首先是启用 EnableBuffering()  关于 EnableBuffering 的官方文档 https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.httprequestrewindextensions.enablebuffering?view=aspnetcore-3.0

主要作用是启用多次读取 Request.Body 以及对 Request.Body 内容设置多大的请求体需要存储到磁盘,具体看文档内容,这里只用到多次读取 Reqeust.Body。

本次做了代码精简以及修复 Response.Body 没有替换回原始 Stream 的 BUG(自己找出来的。。。)

public async Task Invoke(HttpContext context)
{
            context.Request.EnableBuffering();

            _stopwatch.Restart();

            var requestData = new StringBuilder();
            var responseData = new StringBuilder();

            _matchJsonIdKeyValue = new Regex($"{_matchJsonIdExpression}:{_matchJsonIdValueExpression}", RegexOptions.IgnoreCase);
            _matchQueryIdKeyValue = new Regex($"{_matchQueryIdExpression}={_matchQueryIdValueExpression}", RegexOptions.IgnoreCase);

            // 过滤请求
            await FilterRequest(context, context.Request.Body, requestData);

            _stopwatch.Stop();
            Console.WriteLine($"-------------------- Request 解密用时:{_stopwatch.ElapsedMilliseconds}毫秒 --------------------");

            // 将原本的 Response Stream 放入局部变量,因为原本的流不可读
            var originStream = context.Response.Body;
            var replaceStream = new MemoryStream();
            // 替换原本的流
            context.Response.Body = replaceStream;

            // 执行下一个中间件
            await _next(context);

            _stopwatch.Restart();

            // 过滤响应
            await FilterResponse(replaceStream, responseData);

            replaceStream.Dispose();

            // 将解密数据写入原本的 Response 流中
            using (var writer = new StreamWriter(originStream))
            {
                await writer.WriteAsync(responseData.ToString());
                await writer.FlushAsync();
            }
            // 替换回原本的 Stream 
            context.Response.Body = originStream;

            _stopwatch.Stop();
            Console.WriteLine($"======================= 数据加密过程费时:{_stopwatch.ElapsedMilliseconds} 毫秒 =======================");
}
        private async Task FilterResponse(Stream responseStream, StringBuilder responseData)
        {
            using (var reader = new StreamReader(responseStream))
            {
                responseStream.Position = 0;
                responseData.Append(await reader.ReadToEndAsync());
                // 筛选以Id结尾的字段,并将ID加密
                var matchedIdCollection = _matchJsonIdKeyValue.Matches(responseData.ToString());

                foreach (Match itemMathId in matchedIdCollection)
                {
                    var unprotectId = Regex.Match(itemMathId.Value, $"{_matchJsonIdValueExpression}$").Value.Replace("\"", string.Empty);
                    var protectId = Regex.Replace(itemMathId.Value,
                        $"{_matchJsonIdValueExpression}$",
                        $"\"{_dataProtector.Protect(unprotectId)}\"");

                    responseData = responseData.Replace(itemMathId.Value, protectId);
                }
            }
        }
private async Task FilterRequest(HttpContext context, Stream currentRequest, StringBuilder requestData)
        {
            // 可以考虑反序列化为对象,更加灵活控制加密字段,这里使用正则因为 简单,粗暴,快 反射要慢一点

            // 过滤 Get 请求中 QueryString 的 Id 值,并解密
            if (context.Request.Method.Equals(HttpMethods.Get, StringComparison.CurrentCultureIgnoreCase))
            {
                requestData.Append(context.Request.QueryString);
                var matchedIdCollection = _matchQueryIdKeyValue.Matches(requestData.ToString());
                foreach (Match itemMathId in matchedIdCollection)
                {
                    var protectId = Regex.Match(itemMathId.Value, $"{_matchQueryIdValueExpression}$").Value;
                    var unprotectId = Regex.Replace(itemMathId.Value,
                        $"{_matchQueryIdValueExpression}$",
                        $"{_dataProtector.Unprotect(protectId)}");

                    requestData = requestData.Replace(itemMathId.Value, unprotectId);
                }

                context.Request.QueryString = new QueryString(requestData.ToString());
            }
            // 过滤 Post 请求 Body Stream 中的 Id 值,并加密
            if (context.Request.Method.Equals(HttpMethods.Post, StringComparison.CurrentCultureIgnoreCase))
            {
                // 保持这个流打开,不然会导致后续中间件无法打开 Request.Body 流
                using (var reader = new StreamReader(currentRequest, leaveOpen:true))
                {
                    requestData.Append(await reader.ReadToEndAsync());

                    var matchedIdCollection = _matchJsonIdKeyValue.Matches(requestData.ToString());

                    foreach (Match itemMathId in matchedIdCollection)
                    {
                        var protectId = Regex.Match(itemMathId.Value, $"{_matchJsonIdValueExpression}$").Value.Replace("\"", "");
                        var unprotectId = Regex.Replace(itemMathId.Value,
                            $"{_matchJsonIdValueExpression}$",
                            $"\"{_dataProtector.Unprotect(protectId)}\"");

                        requestData = requestData.Replace(itemMathId.Value, unprotectId);
                    }

                    // 重置读取位置
                    currentRequest.Seek(0, SeekOrigin.Begin);
                }
            }

        }

猜你喜欢

转载自www.cnblogs.com/luciusliang/p/11719994.html