如何将 PUT 请求发送到受 OAuth 2.0 和 DotNetOpenAuth 保护的 WCF 4.0 REST 服务
问题:
是否有任何方法(可能是解决方法)来支持使用 OAuth 2.0 和 DotNetOpenAuth 4 保护的 WCF 4.0 REST 服务的 PUT 和 DELETE HTTP 动词?我没有使用 WCF Web API 或 WCF 入门工具包。
到目前为止我所做的事情:
考虑以下 WCF 4.0 REST 服务:
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class MyService
{
[WebGet(UriTemplate = "")]
public List<Resource> GetCollection()
{
/* some implementation */
}
[WebInvoke(UriTemplate = "", Method = "POST")]
public Resource Create(Resource instance)
{
/* some implementation */
}
[WebGet(UriTemplate = "{id}")]
public Resource Get(string id)
{
/* some implementation */
}
[WebInvoke(UriTemplate = "{id}", Method = "PUT")]
public Resource Update(string id, Resource instance)
{
/* some implementation */
}
[WebInvoke(UriTemplate = "{id}", Method = "DELETE")]
public void Delete(string id)
{
/* some implementation */
}
}
OAuth 2.0 用于控制对该服务的访问。它是通过使用 DotNetOpenAuth 完成所有工作的自定义 ServiceAuthorizationManager 实现来实现的。该实现与 DotNetOpenAuth 4.0 示例提供的实现几乎相同。
对于 POST 和 GET 请求,它效果很好。但是,PUT 和 DELETE 请求的请求失败,并显示错误消息:
'AccessProtectedResourceRequest' messages cannot be received with HTTP verb 'PutRequest'
客户端代码看起来类似于:
public class ResourceClient
{
public Resource UpdateResource(Resource resource)
{
var uri = new Uri(new Uri("http://api.example.com/"), Resource.Format("resources/{0}", resource.Id));
var serializer = new DataContractSerializer(typeof(Resource));
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "PUT";
request.ContentType = "application/xml";
ClientBase.AuthorizeRequest(request, Authorization.AccessToken);
using (var requestStream = request.GetRequestStream())
{
serializer.WriteObject(requestStream, resource);
}
using (var response = (HttpWebResponse)request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
Debug.Assert(responseStream != null, "responseStream != null");
return (Resource)serializer.ReadObject(responseStream);
}
}
}
}
从 另一个问题 看来这可能是DotNetOpenAuth 的缺陷。查看 OAuth 2.0 规范,我没有看到任何禁止在访问资源时使用 PUT 或 DELETE http 动词的内容。也就是说,我不是 OAuth 2.0 的专家,也没有记住它。
所以我想我会“聪明”地使用“X-HTTP-Method-Override”来指定PUT,然后将请求POST到资源服务器。我按照此示例。有趣的是,在我的 ServiceAuthorizationManager 实现之前调用了自定义行为,导致了完全相同的错误。
另一种方法是解决 DotNetOpenAuth 本身的问题,但我不知道从哪里开始。
我的想法已经用完了,我将不胜感激任何建议。
The question:
Are there any means (perhaps a workaround) to support the PUT and DELETE HTTP verbs with a WCF 4.0 REST service secured using OAuth 2.0 and DotNetOpenAuth 4? I'm not using the WCF Web API or WCF Starter Kit.
What I have done so far:
Consider the following WCF 4.0 REST Service:
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class MyService
{
[WebGet(UriTemplate = "")]
public List<Resource> GetCollection()
{
/* some implementation */
}
[WebInvoke(UriTemplate = "", Method = "POST")]
public Resource Create(Resource instance)
{
/* some implementation */
}
[WebGet(UriTemplate = "{id}")]
public Resource Get(string id)
{
/* some implementation */
}
[WebInvoke(UriTemplate = "{id}", Method = "PUT")]
public Resource Update(string id, Resource instance)
{
/* some implementation */
}
[WebInvoke(UriTemplate = "{id}", Method = "DELETE")]
public void Delete(string id)
{
/* some implementation */
}
}
OAuth 2.0 is used for controlling access to the service. It is achieved with a custom ServiceAuthorizationManager implementation using DotNetOpenAuth to do all the work. The implementation is almost identical to that provided by the DotNetOpenAuth 4.0 samples.
For POST and GET requests it works great. However, the requests fail for the PUT and DELETE requests with the error message:
'AccessProtectedResourceRequest' messages cannot be received with HTTP verb 'PutRequest'
The client code looks as similar to:
public class ResourceClient
{
public Resource UpdateResource(Resource resource)
{
var uri = new Uri(new Uri("http://api.example.com/"), Resource.Format("resources/{0}", resource.Id));
var serializer = new DataContractSerializer(typeof(Resource));
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "PUT";
request.ContentType = "application/xml";
ClientBase.AuthorizeRequest(request, Authorization.AccessToken);
using (var requestStream = request.GetRequestStream())
{
serializer.WriteObject(requestStream, resource);
}
using (var response = (HttpWebResponse)request.GetResponse())
{
using (var responseStream = response.GetResponseStream())
{
Debug.Assert(responseStream != null, "responseStream != null");
return (Resource)serializer.ReadObject(responseStream);
}
}
}
}
From the answer of another question it seems that this is may be a deficiency in DotNetOpenAuth. Looking at the OAuth 2.0 spec, I don't see anything prohibiting the use of the PUT or DELETE http verbs when accessing resources. That said, I'm not an expert in OAuth 2.0, nor do I know it by heart.
So I thought I would be "clever" and use the "X-HTTP-Method-Override" to specify PUT and then POST the request to the resource server. I implemented the behaviour as explained in this sample. Interestingly enough the custom behavior was called before my ServiceAuthorizationManager implementation, resulting in the exact same error.
An alternative would be to address the issue within DotNetOpenAuth itself, but I have no idea where to start.
I'm running out of ideas and I'd appreciate any suggestions.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这是由问题 #62 跟踪的。如果您想将其移植到您的版本而不等待下一个版本,您可以查看它的修复程序。
This is tracked by Issue #62. You can glance at the fix for it if you want to port it to your version without waiting for the next release.