经过身份验证的服务不支持跨域 javascript 回调。通过 SSL 代理对 WCF 服务的 AJAX 查询
Posted
技术标签:
【中文标题】经过身份验证的服务不支持跨域 javascript 回调。通过 SSL 代理对 WCF 服务的 AJAX 查询【英文标题】:Cross domain javascript callback is not supported in authenticated services. AJAX query to WCF service via SSL proxy 【发布时间】:2013-11-27 12:09:06 【问题描述】:我有一个 WCF / SVC Web 服务,它由通过 AJAX 的 javascript 调用使用。
该页面通过位于 DMZ 中的 SSL 代理 (https://gate.company.com/MyPage
) 访问,然后将请求转发到内部网络服务器 (http://myLocalWebServer/MyPage
)。
经过大量的谷歌搜索和尝试,我能够让它工作,使用参数crossDomainScriptAccessEnabled
和Access-Control-Allow-Origin
。虽然,它仅在身份验证模式设置为 false 或用户尚未登录时才有效。一旦从您需要登录的页面(表单身份验证)中进行调用,它就不再起作用。我得到的错误信息是:
cross domain javascript callback is not supported in authenticated services
但是,一旦我注销并从不受保护的页面进行调用,它就会再次起作用。
我的服务是这样的
namespace MyNameSpace
[ServiceContract(Namespace = "MyNameSpace")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service
[OperationContract]
public string[] GetDropDownData(string id)
List<string> resultList = new List<string>();
...
return resultList.ToArray();
JavaScript 中的服务调用和回调方法:
function fillDropdwon(dropId)
jQuery.ajax(
type: "POST",
dataType: "jsonp",
contentType: "application/json; charset=utf-8",
cache: true,
url: "Service.svc/GetDropDownData",
data: '"dropId":"' + dropId + '"',
jsonpCallback: "onDone",
error: function (a,b,c)
alert("error");
);
// Callback-Methode after ServiceCall
function onDone(result)
var theDropDown = jQuery("#<%= cboSelection.ClientID %>");
if (theDropDown.length > 0)
//Clear the old entries
theDropDown.empty();
//Add an empty entry
if ("<%= cboSelection.ShowEmptyRow %>".toLowerCase() == "true")
theDropDown.append($('<option></option>'));
// Add the found items
for (var i = 0; i < result.length; i++)
var text = result[i];
theDropDown.append($('<option></option>').val(text).html(text));
涉及服务的 web.config 部分:
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="MyNameSpace.ServiceAspNetAjaxBehavior">
<enableWebScript />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<standardEndpoints>
<webScriptEndpoint>
<standardEndpoint crossDomainScriptAccessEnabled="true" name=""/>
</webScriptEndpoint>
</standardEndpoints>
<services>
<service name="MyNameSpace.Service">
<!-- Service endpoint for HTTPS -->
<endpoint address="" behaviorConfiguration="MyNameSpace.ServiceAspNetAjaxBehavior" binding="webHttpBinding" bindingConfiguration="jsonpBinding" contract="MyNameSpace.Service" /> -->
</service>
</services>
<bindings>
<webHttpBinding>
<binding name="jsonpBinding" crossDomainScriptAccessEnabled="true">
<security mode="None" />
</binding>
<binding name="jsonpSslBinding" crossDomainScriptAccessEnabled="true">
<security mode="Transport" />
</binding>
</webHttpBinding>
</bindings>
</system.serviceModel>
我首先尝试使用 ASP.NET AJAX 代理来调用服务,但这不起作用,因为调用是直接对 web 服务器进行的,而不是 SSL,我得到的错误或多或少是:'Page https://gate.company.com/MyPage
试图从页面http://myLocalWebServer/MyPage
加载而不保存内容...'。这就是我使用上面列出的 AJAX 调用的原因。
function fillDropdwon(dropId)
var service = new MyNameSpace.Service();
service.GetDropDownData(dropId, onDone);
我也尝试在 web.config 中添加以下内容
<system.webServer>
<httpProtocol>
<customHeaders>
<!-- Enable Cross Domain AJAX calls -->
<remove name="Access-Control-Allow-Origin" />
<add name="Access-Control-Allow-Origin" value="https://gate.company.com"/>
</customHeaders>
</httpProtocol>
</system.webServer>
我检查了发送到服务器的标头,发现当我未登录时,标头如下所示:
Request URL:`https://gate.company.com/MyPage/Servic.svc/GetDropDownData?callback=onDone`
Request Method:POST
Status Code:200 OK
Request Headersview source
Accept:text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01
Accept-Encoding:gzip,deflate,sdch
Accept-Language:de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4,fr-CH;q=0.2,fr;q=0.2
Connection:keep-alive
Content-Length:161
Content-Type:application/json; charset=UTF-8
Cookie:__utma=174172730.1157990369.1360852643.1381229705.1383150435.9; __utmc=174172730; __utmz=174172730.1369635484.4.3.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided); promopost=oaezz3fzzj0o4l3fccxh0ss1;
ASP.NET_SessionID=
Host:`gate.company.com`
Origin:`https://gate.company.com`
Referer:`https://gate.company.com/MyPage/QuickCalculator.aspx?ObjectIdentity=47a93f52-6be6-4bd6-9600-e8eb9c8ff360`
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.48 Safari/537.36
X-Requested-With:XMLHttpRequest
Query String Parametersview sourceview URL encoded
callback:onDone
Request Payloadview source
dropId:123
dropId: "123"
Response Headersview source
Cache-Control:private
Connection:Keep-Alive
Content-Encoding:gzip
Content-Length:1339
Content-Type:application/x-javascript
Date:Sun, 01 Dec 2013 15:14:25 GMT
Keep-Alive:timeout=15, max=97
Server:Microsoft-IIS/7.5
Vary:Accept-Encoding
X-AspNet-Version:4.0.30319
X-Powered-By
响应看起来像这样。
onDone(["result1","result2"]);
当我从受保护的页面中调用服务时,我得到了这个:
Request URL:`https://gate.company.com/MyPage/Servic.svc/GetDropDownData?callback=onDone`
Request Method:POST
Status Code:200 OK
Request Headersview source
Accept:text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01
Accept-Encoding:gzip,deflate,sdch
Accept-Language:de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4,fr-CH;q=0.2,fr;q=0.2
Connection:keep-alive
Content-Length:161
Content-Type:application/json; charset=UTF-8
Cookie:__utma=174172730.1157990369.1360852643.1381229705.1383150435.9; __utmc=174172730; __utmz=174172730.1369635484.4.3.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided); promopost=oaezz3fzzj0o4l3fccxh0ss1;
**ASP.NET_SessionID=; .ASPXAUTH=AB5ADCE12C7847CA452DD54D903E6787C7D1F0009B9E3277D2EC50DE9C421D1331B87A6DCA2432993933794AB9BDE833E44EC58E217D5AA1D588132C6E1C67D4AD7692840359D9A719EC2A53826CF54FDC0943B4E0AB29093920143E1E987080AC7C35E63594FD678535972D06AEC0AAF74AF8BE8DFC3746B499CB032E7771F10B924110DB344824B3253F9BECB3CDD8**
Host:`gate.company.com`
Origin:`https://gate.company.com`
Referer:`https://gate.company.com/MyPage/QuickCalculator.aspx?ObjectIdentity=47a93f52-6be6-4bd6-9600-e8eb9c8ff360`
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.48 Safari/537.36
X-Requested-With:XMLHttpRequest
Query String Parametersview sourceview URL encoded
callback:onDone
Request Payloadview source
dropId:123
dropId: "123"
Response Headersview source
Cache-Control:private
Connection:Keep-Alive
Content-Encoding:gzip
Content-Length:1339
Content-Type:application/x-javascript
Date:Sun, 01 Dec 2013 15:14:25 GMT
**jsonerror:true**
Keep-Alive:timeout=15, max=97
Server:Microsoft-IIS/7.5
Vary:Accept-Encoding
X-AspNet-Version:4.0.30319
**X-Powered-By:ASP.NET**
响应看起来像这样。
onDone("ExceptionDetail":"HelpLink":null,"InnerException":null,"Message":"Cross domain javascript callback is not supported in authenticated services.","StackTrace":" bei System.ServiceModel.Dispatcher.JavascriptCallbackMessageInspector.AfterReceiveRequest(Message& request, IClientChannel channel, InstanceContext instanceContext)\u000d\u000a bei System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.AfterReceiveRequestCore(MessageRpc& rpc)\u000d\u000a bei System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc& rpc)\u000d\u000a bei System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)","Type":"System.NotSupportedException","ExceptionType":"System.NotSupportedException","Message":"Cross domain javascript callback is not supported in authenticated services.","StackTrace":" bei System.ServiceModel.Dispatcher.JavascriptCallbackMessageInspector.AfterReceiveRequest(Message& request, IClientChannel channel, InstanceContext instanceContext)\u000d\u000a bei System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.AfterReceiveRequestCore(MessageRpc& rpc)\u000d\u000a bei System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc& rpc)\u000d\u000a bei System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)",500);
主要区别在于“已登录”版本有一个 SessionID 和 jsonerror:true。
有办法解决这个问题吗?
是否可以通过在调用之前更改标头或类似的方式来“禁用”AJAX 请求的身份验证。还是我的代码 web.config 中有任何错误?
感谢任何提示,因为我已经尝试了很长时间。
【问题讨论】:
【参考方案1】:我终于找到了解决问题的方法。我写下了我为解决问题所采取的步骤,希望这能帮助遇到类似问题的任何人。
我第一次使用 ASP.NET AJAX 代理并像这样进行调用。
var service = new SDAG.Post.PPT.Website.Service();
service.GetDropDownData(dropId, onDone);
但是,这在我使用 SSL 代理的环境配置中不起作用,该 SSL 代理通过端口 80(如上所列)在内部转发到 Web 服务器。我收到错误消息:
The page at <code>'https://gate.company.com/MyPage/Page.aspx?ObjectIdentity=f5c0c016-4828-4935-a7a9-73f3ba47a1ed'</code> was loaded over HTTPS, but displayed insecure content from <code>'http://myLocalWebServer.company.com/MyPage/Service.svc/GetDropDownData'</code>: this content should also be loaded over HTTPS.
ScriptResource.axd?d=8mniuUQAKIvBIxCF_O9BRQpND31cf-SHqs1HBOCcP0DdxGNo4-nOZcF0WZIDoCtTdw5mZiost0veif…:2
OPTIONS <code>http://myLocalWebServer.company.com/MyPage/Service.svc/GetDropDownData</code> 405 (Method Not Allowed) ScriptResource.axd?d=8mniuUQAKIvBIxCF_O9BRQpND31cf-SHqs1HBOCcP0DdxGNo4-nOZcF0WZIDoCtTdw5mZIOSt0veif…:2
OPTIONS <code>http://myLocalWebServer.company.com/MyPage/Service.svc/GetDropDownData</code> No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin <code>'https://gate.company.com'</code> is therefore not allowed access. ScriptResource.axd?d=8mniuUQAKIvBIxCF_O9BRQpND31cf-SHqs1HBOCcP0DdxGNo4-nOZcF0WZIDoCtTdw5mZIOSt0veif…:2
XMLHttpRequest cannot load <code>http://myLocalWebServer.company.com/MyPage/Service.svc/GetDropDownData</code>. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin <code>'https://gate.company.com'</code> is therefore not allowed access. Page.aspx?ObjectIdentity=f5c0c016-4828-4935-a7a9-73f3ba47a1ed:1
Refused to get unsafe header "jsonerror"
我发现通过在 web.config 的 webservice 绑定配置中使用 crossDomainScriptAccessEnabled
并通过 jQuery 使用 Jsonp Ajax 调用,它确实有效(代码见上文)
但是:它只在页面的非授权区域有效。一旦用户在登录页面上进行了身份验证,调用就不再起作用了。它告诉我Cross domain javascript callback is not supported in authenticated services
。
最后,我找到了解决方案。
错误消息来自 web.config 中配置的crossDomainScriptAccessEnabled
。当我删除它时,jsonp 调用不再起作用。所以我所做的是删除 crossDomainScriptAccessEnabled
并用常规 json-call 替换 jsonp-call。
jQuery.ajax(
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
cache: true,
url: "Service.svc/GetDropDownData",
data: '"dropId":"' + dropId + '"',
error: function (xhr, textStatus, errorThrown)
// Ignore in my case...
,
success: function (data, textStatus, xhr)
fillSubList(data.d);
);
function fillSubList(result)
var theDropDown = jQuery("#<%= cboSelektion.ClientID %>");
if (theDropDown.length > 0)
//Clear the old entries
theDropDown.empty();
//Add the empty one
if ("<%= cboSelektion.ShowEmptyRow %>".toLowerCase() == "true")
theDropDown.append($('<option></option>'));
// Add the found items
for (var i = 0; i < result.length; i++)
var text = result[i];
theDropDown.append($('<option></option>').val(text).html(text));
【讨论】:
删除配置绑定中的crossDomainScriptAccessEnabled
属性为我修复了它。以上是关于经过身份验证的服务不支持跨域 javascript 回调。通过 SSL 代理对 WCF 服务的 AJAX 查询的主要内容,如果未能解决你的问题,请参考以下文章