WCF REST 服务中的 CORS 支持

Posted

技术标签:

【中文标题】WCF REST 服务中的 CORS 支持【英文标题】:CORS Support within WCF REST Services 【发布时间】:2011-11-06 06:27:43 【问题描述】:

我有一个托管在 Windows 服务中的 WCF REST 服务,我想在每个响应中发送 Access-Control-Allow-Origin HTTP 标头(定义为CORS 的一部分)。

我尝试的解决方案是在 IDispatchMessageInspector 实现中包含以下内容:

public void BeforeSendReply(ref Message reply, object correlationState)

    var httpResponse = reply.Properties["httpResponse"] as HttpResponseMessageProperty;
    if (httpResponse != null)
    
        // test of CORS
        httpResponse.Headers["Access-Control-Allow-Origin"] = "*";
    

通常这会起作用,但不幸的是我的服务也使用HTTP basic authorization,这意味着当没有授权标头的请求进入时,WCF 会自动发送一个 401 响应,要求提供凭据。不幸的是,WCF 在此初始交换期间没有调用我的 IDispatchMessageInspector,因此 Access-Control-Allow-Origin 标头不会添加到初始交换中。

当我尝试从浏览器调用服务时出现问题。 CORS 指定仅当源域与 Access-Control-Allow-Origin 响应标头中列出的域匹配时才允许跨域请求(* 匹配所有域)。不幸的是,当浏览器看到没有 Access-Control-Allow-Origin 标头的初始 401 响应时,它会阻止访问(根据same origin policy)。

有没有办法在 WCF 自动发送的初始 401 响应中添加标头?

【问题讨论】:

你有没有得到任何地方? 【参考方案1】:

要实现您想要的,您需要自己处理授权,这可以通过实施 + 注册 HttpModule 来实现...在那里您将发出 401 以及您想要的任何 http 标头...甚至还有一个示例在 SO 上实现 - 请参阅 Adding basic HTTP auth to a WCF REST service

编辑 - 来自 OP 的评论后:

由于 OP 的评论说他是自托管的,因此解决方案不是使用 HTTPModule,而是使用 IDispatchMessageInspector.BeforeSendReplyIDispatchMessageInspector.AfterReceiveRequest

授权必须配置为“无”并在IDispatchMessageInspector 中自定义实现/处理 - 这样您可以在发出 401 时添加任何标头。否则运行时处理基本身份验证不会在正确/肯定身份验证之前调用您的IDispatchMessageInspector

虽然这可行,但请注意,这意味着您自己实现了对安全敏感的代码,因此需要采取适当的措施来确保其正确实现......

【讨论】:

感谢您的回复。我的服务需要是自托管的 Windows 服务,而不是托管的 IIS。我的服务中的 HTTP 基本身份验证内容效果很好。 CORS 也可以正常工作(假设我禁用了基本身份验证)。只有在自托管服务上混合 HTTP 基本和 CORS 时才会出现此问题。如果我要在 IIS 中托管服务,我会配置 IIS 以在每个请求上发送 CORS 响应标头,并使用 HttpModule 进行 HTTP 基本身份验证。 好的 - 查看我的编辑...您的解决方案已经完成了一半...您需要实现另一种方法并更改配置... 设置 clientCredentialType="None" 并手动进行检查几乎可以正常工作。您可以发送 401 回复,但 WCF 不允许您设置 WWW-Authenticate 响应标头。尝试在代码中设置 WWW-Authenticate 会导致 WCF 返回 504。如果没有 WWW-Authenticate,浏览器将不会提示输入凭据。 很抱歉,但那对我来说已经结束了 - 我没有更多的想法......除了在 IIS 中托管并使用 HttpModule 方法...... 是的,我怀疑这可能是不可能的。我也尝试使用 HttpListener 而不是 WCF,它有相同的 WWW-Authenticate 问题。感谢您的想法。【参考方案2】:

这个人拯救了我的一天。

http://blogs.microsoft.co.il/blogs/idof/archive/2011/07.aspx

我将把他的一些笔记放在这里,以防万一该网页有一天会死掉。 (我讨厌找到“你的答案就在这里”链接,然后链接就失效了。)

<behaviors> 
  <endpointBehaviors> 
    <behavior name="webSupport"> 
      <webHttp /> 
      <CorsSupport /> 
    </behavior> 
  </endpointBehaviors> 
</behaviors> 
<extensions> 
  <behaviorExtensions> 
    <add name="CorsSupport" type="WebHttpCors.CorsSupportBehaviorElement, WebHttpCors, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 
  </behaviorExtensions> 
</extensions> 
<services> 
  <service name="Service.JSonService"> 
    <endpoint address="http://localhost:8080" behaviorConfiguration="webSupport” binding="webHttpBinding" contract="Service.IJSonService" /> 
  </service> 
</services>

现在,你必须找到他的名为“WebHttpCors.dll”的可下载库。

但是(上面)有足够的内容可以帮助您通过 google/bing 找到解决方案。

让我陷入循环的部分(在我的场景中)是 IE 可以工作,但 Firefox 不能工作。

我的原始页面是:

http://localhost:53692/test/WCFCallTestViaJQ14.htm

所以我的服务在:

http://localhost:8002/MyWCFService/MyWCFMethodByWebGet?state=NC&city=Raleigh

所以我有 localhost > localhost 流量。

**** 但是端口不同。 (53692 和 8002)****

IE 没问题。 Firefox 不适合它。

那么你必须记住每个浏览器处理它们的 .Send() 请求是不同的(在 JQUERY 内部)。

现在一切都说得通了。

//javascript snipplet from JQuery library

if (window.XMLHttpRequest) 

    returnObject = new XMLHttpRequest();

 else if (window.ActiveXObject) 

    returnObject = new ActiveXObject("Microsoft.XMLHTTP");

 else 

msg = "Your browser doesn't support AJAX!";


这里有一些关键词、短语,我一直在谷歌搜索/搜索,最终将我带到了某个地方。

    Result: [Exception... "Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIXMLHttpRequest.statusText]" nsresult: "0x80040111 (NS_ERROR_NOT_AVAILABLE)" location: "JS frame :: http://localhost:53692/test/WCFCallTestViaJQ14.htm :: HandleJQueryError :: line 326" data: no]


XMLHttpRequest Send "NS_ERROR_FAILURE"

JQuery Ajax WCF Self Hosted CORS JSON

现在,您需要阅读他的博客来了解代码的作用:

例如,他说:

值为“*”的“Access-Control-Allow-Origin”标头

这可能是也可能不是您想要的。您可能希望更好地控制此值(标头)和其他值(方法和来源)。

开发环境是一回事。 (使用所有你想要的 *)。

生产是另一回事,您可能希望将这些 * 值调整为更具区分性的值。简而言之,您需要了解 CORS 在安全方面实际上为您做了什么,而不仅仅是添加一个让一切都进入的行为。

  allowed-origins: '*'
  allowed-headers: '*'
  allowed-methods: '*'

【讨论】:

支持所有细节。继续与链接失效作斗争!【参考方案3】:

将以下行添加到 WCF 服务中调用的第一个方法对我有用。

WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");

需要以下导入

System.ServiceModel.Web;

Refer this for original answer

【讨论】:

【参考方案4】:

我尝试了很多方法但找不到任何东西,然后突然间我终于知道应该只通过 OPTIONS 请求发送标头,然后我找到了一些有用的 SO 代码here! 这个完全解决了我的问题。

实际上这里的重点是您必须在 OPTIONS 请求中添加标头以及 200 OK 响应,这就是在此链接上所做的。

【讨论】:

以上是关于WCF REST 服务中的 CORS 支持的主要内容,如果未能解决你的问题,请参考以下文章

CORS 启用 WCF REST 和 Kendo

REST WCF 服务中的事务

具有 CORS 和基本身份验证支持的 WCF 自托管数据服务

使用 AngularJs 调用 WCF REST 服务给出错误

Ajax POST 到 WCF Rest CORS 兼容的 WebService 引发错误 405

WCF 的哪一部分处理身份验证?