WebApi传参总动员(填坑)

本以为系列文章已经Over,突然记起来前面留了个大坑还没填,真是自己给自己挖坑。

这个坑就是:

(body 只能被读取一次)Only one thing can read the body
MVC和WebAPI之间的一个关键不同点在于MVC缓存请求主体(request body)。这意味着MVC的参数绑定可以反复从body中查找参数片断。然而,在WebAPI中,请求主体(HttpContent)

只能被读取一次,不被缓存,只能向前读取的流。这意味着parameter binding需要谨慎对待stream,除非在需要绑定参数的情况下,否则stream不能被读取。

以下的action方法想直接读取stream,因而导致WebAPI不能保证其拥有用于参数绑定的stream。
引自:

[译]WebAPI下的如何实现参数绑定


这也就意味着,凡是参数中含有实体类型的,这个实体只能获取一次。

话说园子里WebApi安全性的文章也不少了,可是这个坑少有人提,也不晓得为啥,只好自己走一个大弯路先。

本人所在公司目前用MVC开发,Api做安全验证的时候,是将验证的系统参数和数据一起打包成一个匿名类,在Attribute中做验证,是可行的。同样的方式,拿到WebApi中,就死活走不下去。因为在ActionFilterAttribute中用请求的输入流(貌似只能以此种办法)获取实体后,在Action中就拿不到真正的数据了。

经过调整后的验证代码:

        /// WebAPI防篡改签名验证抽象基类Attribute

        /// </summary>
        public override void OnActionExecuting(HttpActionContext actionContext)
        {

            //获取Asp.Net对应的Request

            var request = ((HttpContextWrapper)actionContext.Request.Properties["MS_HttpContext"]).Request;

            NameValueCollection getCollection = request.QueryString;//此签名要求client_id、token及timestamp均通过QueryString传递
            string outMessage = "未经过验证的请求!";
            if (getCollection != null && getCollection.Count > 0)
            {

                string client_id = getCollection["client_id"];
                string timestamp = getCollection["timestamp"];
                string token = getCollection["token"];
                if (!string.IsNullOrWhiteSpace(client_id)//必须包含client_id
                   && !string.IsNullOrWhiteSpace(timestamp)//必须包换时间戳

                   && !string.IsNullOrWhiteSpace(token))
                //&& Regex.IsMatch(client_key, "^[0-9A-Za-z]{32}$"))//sign必须为32位Md5摘要
                {
                    Config.Service.SignCalculation sc = new Config.Service.SignCalculation();
                    if (sc.VerifyClientParam(client_id, token, timestamp, out outMessage))
                    {//验证通过,执行基类方法
                        base.OnActionExecuting(actionContext);
                        return;
                    }
                }
                var html = "<p>" + outMessage + "</p>";

                
                //此处暂时以401返回,可调整为其它返回
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized,"验证失败");
                actionContext.Response.Content = new StringContent(html, Encoding.UTF8, "text/html");
            }
        }
View Code

调整后,验证参数从请求QueryString中获得,Action可以用本系列的几种办法均可以顺利获取实际的数据。

填坑完毕。

本系列为本人原创,解决了本人实际工作中碰到的问题。

写文章不易,欢迎转载。但转载的时候,带上原文链接,可好?

原文地址:https://www.cnblogs.com/luhuanong/p/4930539.html