标签:
本以为系列文章已经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安全性的文章也不少了,可是这个坑少有人提,也不晓得为啥,只好自己走一个大弯路先。
本人所在公司目前用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"); } }
调整后,验证参数从请求QueryString中获得,Action可以用本系列的几种办法均可以顺利获取实际的数据。
填坑完毕。
本系列为本人原创,解决了本人实际工作中碰到的问题。
写文章不易,欢迎转载。但转载的时候,带上原文链接,可好?
标签:
原文地址:http://www.cnblogs.com/luhuanong/p/4930539.html