首页 > 其他分享 >MVC和.net6,API的body在过滤器中重复消费

MVC和.net6,API的body在过滤器中重复消费

时间:2024-03-21 10:25:25浏览次数:19  
标签:body return string postData timestamp await MVC actionContext API

在MV中

private async Task<string> ReadPostDataAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
        {
            string postData = "";
            var requestStream = await actionContext.Request.Content.ReadAsStreamAsync();
            byte[] bytes = new byte[requestStream.Length];
            requestStream.Read(bytes, 0, bytes.Length);
            //设置当前流的位置为流的开始
            requestStream.Seek(0, SeekOrigin.Begin);

            //将bytes转换为流(生成新的Stream,防止读取一次就被清空数据了)
            Stream newStream = new MemoryStream(bytes);
            using (newStream)
            {
                if (newStream.Length > 0)
                {
                    var byts = new byte[newStream.Length];
                    newStream.Read(byts, 0, (int)byts.Length);
                    postData = Encoding.UTF8.GetString(byts);
                }
            }
            return postData;
        }

 

在.NET6中

context.HttpContext.Request.EnableBuffering();
string bodyStr = string.Empty;
request.EnableBuffering();//允许多次读取HTTP请求的正文
using (var reader = new StreamReader(request.Body,
                                     encoding: Encoding.UTF8,
                                     detectEncodingFromByteOrderMarks: false,
                                     leaveOpen: true)
      )
{
    bodyStr = await reader.ReadToEndAsync();
    request.Body.Position = 0;
}
string secretpost = apisecret + timestamp.ToString() + bodyStr;

 

最后附上MVC和.NET6,WEBAPI加密全部代码

MVC

public class BasicWebApiAuthorize : AuthorizeAttribute
    {
        /// <summary>
        /// 接口加密签名
        /// </summary>
        public string SecretKey = "XXXXXXXXXXXXX";

        public override async Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
        {
            try
            {
                var headers = actionContext.Request.Headers;
                if (!TryGetHeaderValue(headers, "timestamp", out string timestamp)
                    || !TryGetHeaderValue(headers, "sign", out string sign))
                {
                    await HandleInvalidRequestAsync(actionContext, "请求Header参数无效", cancellationToken);
                    return;
                }

                if (!ValidateTimestamp(timestamp))
                {
                    await HandleInvalidRequestAsync(actionContext, "时间戳无效", cancellationToken);
                    return;
                }

                string postData = await ReadPostDataAsync(actionContext, cancellationToken);

                if (string.IsNullOrEmpty(postData))
                {
                    await HandleInvalidRequestAsync(actionContext, "请求参数为空", cancellationToken);
                    return;
                }
                if (!ValidateSign(postData, timestamp, sign))
                {
                    await HandleInvalidRequestAsync(actionContext, "签名无效", cancellationToken);
                    return;
                }

                if (!IsUnderAttack(postData))
                {
                    await LogAndSendWorkWxMsg(actionContext, $"存在被攻击内容({postData})");
                    await HandleInvalidRequestAsync(actionContext, "内容无效", cancellationToken);
                    return;
                }
            }
            catch (Exception ex)
            {
                LoggerHelper.Error("授权验证过程中出现错误", ex);
                await HandleServerErrorAsync(actionContext, cancellationToken);
            }

        }
        private async Task<string> ReadPostDataAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
        {
            string postData = "";
            var requestStream = await actionContext.Request.Content.ReadAsStreamAsync();
            byte[] bytes = new byte[requestStream.Length];
            requestStream.Read(bytes, 0, bytes.Length);
            //设置当前流的位置为流的开始
            requestStream.Seek(0, SeekOrigin.Begin);

            //将bytes转换为流(生成新的Stream,防止读取一次就被清空数据了)
            Stream newStream = new MemoryStream(bytes);
            using (newStream)
            {
                if (newStream.Length > 0)
                {
                    var byts = new byte[newStream.Length];
                    newStream.Read(byts, 0, (int)byts.Length);
                    postData = Encoding.UTF8.GetString(byts);
                }
            }
            return postData;
        }
        private async Task HandleInvalidRequestAsync(HttpActionContext actionContext, string errorMessage, CancellationToken cancellationToken)
        {
            await LogAndSendWorkWxMsg(actionContext, errorMessage);
            actionContext.Response = await Task.Run(() => getResultContent(400, errorMessage), cancellationToken);
        }
        private bool TryGetHeaderValue(HttpRequestHeaders headers, string key, out string value)
        {
            IEnumerable<string> values;
            if (headers.TryGetValues(key, out values) && values.Any())
            {
                value = values.First();
                return true;
            }
            value = null;
            return false;
        }
        private bool ValidateTimestamp(string timestamp)
        {
            //验证时间戳是否合法
            var timeDate = TimeConvertor.ConvertIntDatetime(Convert.ToDouble(timestamp));
            var diffNow = (DateTime.Now - timeDate).TotalMilliseconds;
            if (diffNow < -60000 || diffNow > 60000)//6秒内有效
            {
                return false;
            }
            // 时间戳验证逻辑...
            return true; // 填充实际的验证逻辑
        }

        private bool ValidateSign(string postData, string timestamp, string sign)
        {
            // 签名验证逻辑...
            //验证签名是否有效
            var _sign = StringHelper.EncryptToMD5Lowercase32($"{postData}{timestamp}{SecretKey}");
            if (_sign.ToLower() != sign.ToLower())
            {
                return false;
            }
            return true; // 填充实际的验证逻辑
        }

        private bool IsUnderAttack(string postData)
        {
            // SQL注入检查逻辑...
            if (postData.ToLower().Contains("select ") || postData.ToLower().Contains("update ") ||
            postData.ToLower().Contains("delete ") || postData.ToLower().Contains("drop "))
            {
                return false;
            }
            return true; // 填充实际的检查逻辑
        }
        private async Task LogAndSendWorkWxMsg(HttpActionContext actionContext, string errorMessage)
        {
            StringBuilder log = new StringBuilder();
            log.AppendLine("接口请求失败:" + errorMessage);
            log.AppendLine($"接口名:{actionContext.Request.RequestUri}");
            LoggerHelper.Error(log.ToString());
        }
        private async Task HandleServerErrorAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
        {
            actionContext.Response = await Task.Run(() => getResultContent(500, "服务器内部错误"), cancellationToken);
        }

        private HttpResponseMessage getResultContent(int error_code = 0, string message = "ok")
        {
            var actionResult = new HttpResponseMessage();
            var result = new
            {
                error_code = error_code,
                message = message
            };
            actionResult.Content = new StringContent(JsonConvert.SerializeObject(result), Encoding.GetEncoding("UTF-8"), "application/json");

            return actionResult;
        }
    }

 

.NET6中

public class OpenApiHashaFilter : Attribute, IAsyncAuthorizationFilter
{
    public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {

        var request = context.HttpContext.Request;

        //发起请求的时间戳  单位(秒)
        string timestamp = GetHeaderValue(request.Headers, "timestamp");
        //Md5加密后的字符串
        string signature = GetHeaderValue(request.Headers, "signature");

        if (string.IsNullOrEmpty(timestamp) || string.IsNullOrEmpty(signature))
        {
            await HandleUnauthorized(context, "请求缺少重要的header信息");
            return;
        }
        if (!DateTime.TryParse(timestamp, out DateTime parsedTimestamp))
        {
            await HandleUnauthorized(context, "时间戳格式不正确");
            return;
        }

        if (!IsTimestampValid(parsedTimestamp))
        {
            await HandleUnauthorized(context, "接口请求时间超过规定时间");
            return;
        }

        bool isValidSignature = await ValidateRequestAsync(request, timestamp, signature);

        if (!isValidSignature)
        {
            await HandleUnauthorized(context, "接口请求失败,签名错误,无法请求接口");
            return;
        }
    }
    private async Task<bool> ValidateRequestAsync(HttpRequest request, string timestamp, string signature)
    {
        string apisecret = AppSettingHelper.ReadAppSettings("Open", "hmac_secret");
        string data = string.Empty;
        if (request.Method == HttpMethods.Get)
        {
            data = request.GetEncodedUrl();
        }
        else
        {
            request.EnableBuffering();

            using (var reader = new StreamReader(request.Body,
                                                 encoding: Encoding.UTF8,
                                                 detectEncodingFromByteOrderMarks: false,
                                                 leaveOpen: true))
            {
                data = await reader.ReadToEndAsync();
                request.Body.Position = 0;
            }
        }

        return ValidateSignature(timestamp, signature, apisecret, data);
    }

    private static string GetHeaderValue(IHeaderDictionary headers, string key)
    {
        if (headers.TryGetValue(key, out var values) && values.Any())
        {
            return HttpUtility.UrlDecode(values.FirstOrDefault());
        }
        return null;
    }

    private async Task HandleUnauthorized(AuthorizationFilterContext context, string errorMessage)
    {
        context.Result = new ObjectResult(new { error = "Unauthorized", errorMessage })
        {
            StatusCode = StatusCodes.Status401Unauthorized
        };
        await Task.CompletedTask;
    }
    private bool IsTimestampValid(DateTime timestamp)
    {
        TimeSpan timeSpan = DateTime.UtcNow - timestamp.ToUniversalTime();
        return timeSpan.TotalSeconds <= 120; // 考虑两分钟内的有效时间窗口
    }

    private bool ValidateSignature(string timestamp, string signature, string secretKey, string data)
    {
        string secretpost = $"{secretKey}{timestamp}{data}";
        string calculatedMd5 = SecretHepler.EncryptToMD5Lowercase32(secretpost);

        return calculatedMd5.ToUpper() == signature.ToUpper();
    }
}

 

标签:body,return,string,postData,timestamp,await,MVC,actionContext,API
From: https://www.cnblogs.com/bugenniduobb/p/18086641

相关文章

  • net core Web API 使用 Redis
    1.新建WebAPIapi2.新建类库Service安装StackExchange.Redis2.1Service中新建Redis文件夹,并创建接口IRedisService和类RedisSerivce点击查看代码publicinterfaceIRedisService{//获取Redis缓存值stringGetValue(stringkey);//获取值,并序列化TE......
  • 汇编语言中的MVC
    一MVC指令1.移动字符串指令MVC移动字符串指令MVC的格式为:MVCD1(L,B1),D2(B2)(移动字符串)功能:(D1+(B1))←(D2+(B2))L个字符指令的执行用开始于D2(B2)的L字节替换开始于D1(B1)的L字节的内容。L个字节的内容每次改变一个,从左边开始。如果域不重叠的话,这一事实是不重要的,但......
  • 深入理解 SpringMVC
    前言SpringMVC可以说是我们日常开发中最依赖的Spring组件了,它基于Servlet容器实现,允许我们通过注解的方式开发Web程序。在本篇文章,将深入SpringMVC源码,梳理SpringMVC对Web请求处理流程,弄懂相关核心组件的原理,最终做到在使用的时候知其然也知其所以然。一、接受并分......
  • Salesforce LWC学习(四十九) RefreshView API实现标准页面更新,自定义组件自动捕捉更新
    本篇参考: https://developer.salesforce.com/docs/platform/lwc/guide/data-refreshview.htmlhttps://developer.salesforce.com/docs/platform/lwc/guide/reference-lightning-refreshview.htmlhttps://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007KX6dA......
  • 云打印api介绍,云打印api有什么优势?
    最近很多开发者朋友在网上问询云打印api的相关问题,还有很多朋友不太了解云打印api。那么今天我们就来给大家介绍一下,云打印api是什么?云打印api有什么优势? 云打印api是什么?云打印api有什么优势?云打印api即云打印应用程序接口,通过对接云打印api即可让开发者在其应用程序中集成......
  • php 对接Unity海外广告平台收益接口Reporting API
    今天对接的是Unity广告reportingapi接口,拉取广告收益回来自己做统计。记录分享给大家首先是文档地址,进入到Unity后台就能看到文档地址以及参数:文档地址:https://docs.unity.com/ads/en-us/manual/MonetizationStatsAPI在这里插入图片描述接入这些第三方广告平台,流程基......
  • openai免费API-openai api key获取!开箱即用!
    最近又开始准备整些东西要用到apikey,才发现过我的大洋过期了!痛心......
  • 全栈的自我修养 ———— js中的拖拽api
    今天让我们试一下js中的比较有趣味的拖拽api,用他来做成一个课程表!一、实现目标二、过程1、html实现第一步第二步js实现三、源码一、实现目标二、过程1、html实现第一步创建一个container的拖拽区域,左边准备放课程,然后给每一个div设置同一个draggable为truetrue......
  • Collider和Rigidbody组件相关
    Rigidbodydynamic类型开销最大的类型拥有完整的功能(现实世界相同的物体)会和所有类型的刚体碰撞会受到各种力的影响kinematic类型仍然通过速度移动但并不受到任何力的影响也只会与dynamic发生碰撞,发生碰撞时近似于无限质量的物体(不会改变运动状态)static类型本意......
  • 【APIM】Azure API Management Self-Host Gateway是否可以把请求的日志发送到Applicat
    问题描述AzureAPIManagementSelf-HostGateway是否可以把请求的日志发送到ApplicationInsights呢?让它和使用Azure上托管的Gateway一样呢?这是在APIM门户上配置API,设置的DiagnosticsLogs,当选择ApplicationInsights时,就可以把对接口请求时候所携带的Header/Body等信息发送......