使用 Windows 身份验证的 WCF jsonP - 可能吗?

发布于 2024-12-12 13:42:02 字数 1142 浏览 1 评论 0原文

我正在托管一个输出 jsonp 的 wcf 服务。来自 IIS(打开 Windows 身份验证)的响应是

经过身份验证的服务不支持跨域 javascript 回调。

有办法解决这个问题吗?我必须打开 Windows 身份验证,但也想使用 wcf 来服务器我的 jsonp

我的 Web 配置如下

<system.serviceModel>
  <behaviors>
    <endpointBehaviors>
      <behavior name="webHttpBehavior">
        <webHttp />
      </behavior>
    </endpointBehaviors>
  </behaviors>
  <bindings>
    <webHttpBinding>
      <binding name="webHttpBindingWithJsonP" crossDomainScriptAccessEnabled="true" >
        <security mode="TransportCredentialOnly">
          <transport clientCredentialType="Ntlm"/>
        </security>
      </binding>
    </webHttpBinding>
  </bindings>
  <services>
    <service name="ServiceSite.CustomersService">
      <endpoint address="" binding="webHttpBinding"
                bindingConfiguration="webHttpBindingWithJsonP" contract="ServiceSite.CustomersService"
                behaviorConfiguration="webHttpBehavior"/>
    </service>
  </services>
</system.serviceModel>

I am hosting a wcf service which outputs jsonp. The response from IIS (with windows authentication turned on) is

Cross domain javascript callback is not supported in authenticated services.

Is there a way to work around this? I must have windows authentication turned on but would like to use wcf as well to server my jsonp

My web config is as follows

<system.serviceModel>
  <behaviors>
    <endpointBehaviors>
      <behavior name="webHttpBehavior">
        <webHttp />
      </behavior>
    </endpointBehaviors>
  </behaviors>
  <bindings>
    <webHttpBinding>
      <binding name="webHttpBindingWithJsonP" crossDomainScriptAccessEnabled="true" >
        <security mode="TransportCredentialOnly">
          <transport clientCredentialType="Ntlm"/>
        </security>
      </binding>
    </webHttpBinding>
  </bindings>
  <services>
    <service name="ServiceSite.CustomersService">
      <endpoint address="" binding="webHttpBinding"
                bindingConfiguration="webHttpBindingWithJsonP" contract="ServiceSite.CustomersService"
                behaviorConfiguration="webHttpBehavior"/>
    </service>
  </services>
</system.serviceModel>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

全部不再 2024-12-19 13:42:02

我明白了,有点晚了,但由于没有发布答案,而且我遇到了类似的问题:

The only way I was able to use a windows-authenticated WCF service (hosted in IIs 7.5) that was accessed from a cross-domain client是让客户通过代理进行呼叫。有一个额外的跃点返回代理,但现在我不再依赖 JSONP。该服务设置有两个端点:soap 和 json - 我将整个 serviceModel 放在底部以供参考。

因此,客户端应用程序(都是 .NET Web 应用程序)要么:

A) 将 $.ajax POST 发送到页面方法(或 [HttpPost] MVC 控制器方法),该方法调用 WCF 作为肥皂 Web 引用:

function EmployeeSearch() {
    var searchname = $("#userSearchText").val();
    if (searchname.length > 0) {
        var d = { name: searchname, pageSize: _pageSize, page: _currentPage };
        var jsonData = JSON.stringify(d);
        if (json.length > 0) {
            $.ajax({
                type: "POST",
                url: "Home/EmployeeSearch",
                data: jsonData,
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: employeeSearchSuccess,
                error: onError
            });
        }
    }
}

以及控制器方法(或页面方法):

    [HttpPost]
    public ActionResult EmployeeSearch(string name, int pageSize, int page)
    {
        var client = new EmployeeServiceClient();
        var searchResult = client.EmployeeSearch(name);
        var count = searchResult.Count();
        var employees = searchResult.Skip((page - 1) * pageSize).Take(pageSize).ToList();

        var viewModel = new EmployeeSearchViewModel
                            {
                                Employees = employees,
                                Size = count
                            };

        return Json(viewModel);
    }

B) 将 $.getJSON 创建为 HttpHandler,如 Dave Wards http://encosia.com/use-asp- nets-httphandler-to-bridge-the-cross-domain-gap/

在上面的示例中,处理程序的 ProcessRequest 方法中的 WebClient.DownoadString() 将采用以下 url 字符串:

http://server/EmployeeService/EmployeeService.svc/Json/EmployeeSearch/searchstring

两种方法允许我的服务保留在 Windows 身份验证下,并且客户端有几种访问该服务的方法。额外的跳跃很烦人,但我尽量不去想它。

这里是整个 WCF 服务模型供参考:

<behaviors>
    <serviceBehaviors>
        <behavior name="EmployeeServiceBehavior">
            <serviceTimeouts transactionTimeout="01:00:00"/>
            <serviceMetadata httpGetEnabled="true"/>
            <serviceDebug includeExceptionDetailInFaults="true"/>
            <dataContractSerializer maxItemsInObjectGraph="2147483647"/>
        </behavior>
    </serviceBehaviors>

    <!-- we'd use this one if we wanted to ignore the 'd' wrapper around the json result ... we don't -->
    <endpointBehaviors>
        <!-- plain old XML -->
        <behavior name="poxBehavior">
            <webHttp helpEnabled="true" />
        </behavior>
        <!-- JSON -->
        <behavior name="jsonBehavior">
            <enableWebScript />
        </behavior>
    </endpointBehaviors>

</behaviors>

<bindings>
    <basicHttpBinding>
        <binding name="basicBinding"
                hostNameComparisonMode="StrongWildcard"
                receiveTimeout="00:10:00"
                sendTimeout="00:10:00"
                openTimeout="00:10:00"
                closeTimeout="00:10:00"
                maxReceivedMessageSize="2147483647"
                maxBufferSize="2147483647"
                maxBufferPoolSize="524288"
                transferMode="Buffered"
                messageEncoding="Text"
                textEncoding="utf-8"
                bypassProxyOnLocal="false"
                useDefaultWebProxy="true" >
            <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
            <!-- use the following for windows authentication -->
            <security mode="TransportCredentialOnly">
                <transport clientCredentialType="Windows" />
            </security>
        </binding>
    </basicHttpBinding>

    <webHttpBinding>
        <binding name="webBinding"
                receiveTimeout="00:10:00"
                sendTimeout="00:10:00"
                openTimeout="00:10:00"
                closeTimeout="00:10:00"
                maxReceivedMessageSize="2147483647"
                maxBufferSize="2147483647"
                maxBufferPoolSize="524288"
                bypassProxyOnLocal="false"
                useDefaultWebProxy="true"
                >
            <!--crossDomainScriptAccessEnabled="true"-->
            <!-- use the following for windows authentication -->
            <security mode="TransportCredentialOnly">
                <transport clientCredentialType="Windows" />
            </security>
        </binding>
    </webHttpBinding>

</bindings>

<services>
    <service name="EmployeeService.Wcf.EmployeeService" behaviorConfiguration="EmployeeServiceBehavior">
        <endpoint address="Soap" binding="basicHttpBinding" bindingConfiguration="basicBinding" contract="EmployeeService.Wcf.IEmployeeService"/>
        <endpoint address="Json" binding="webHttpBinding" bindingConfiguration="webBinding" behaviorConfiguration="poxBehavior" contract="EmployeeService.Wcf.IEmployeeService" />
    </service>
</services>

<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true"/>

补充一点 - 上述示例方法的 OperationContract 在 ServiceContract 中设置如下:

    [OperationContract]
    [WebInvoke(Method = "GET", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, UriTemplate = "EmployeeSearch/{name}")]
    List<Employee> EmployeeSearch(string name);

A bit late, I see, but since there are no answers posted and I encountered a similar problem:

The only way I was able to use a windows-authenticated WCF service (hosted in IIs 7.5) that was accessed from a cross-domain client was to have the clients call through a proxy. There’s an extra hop back to the proxy, but now I no longer rely on JSONP. The service is setup with two endpoints, soap and json – I stuck the entire serviceModel at the bottom for reference.

So the client apps (which are all .NET web apps) either:

A) Make an $.ajax POST to a page method (or [HttpPost] MVC controller method) which calls the WCF as a soap web reference:

function EmployeeSearch() {
    var searchname = $("#userSearchText").val();
    if (searchname.length > 0) {
        var d = { name: searchname, pageSize: _pageSize, page: _currentPage };
        var jsonData = JSON.stringify(d);
        if (json.length > 0) {
            $.ajax({
                type: "POST",
                url: "Home/EmployeeSearch",
                data: jsonData,
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: employeeSearchSuccess,
                error: onError
            });
        }
    }
}

And the controller method (or page method):

    [HttpPost]
    public ActionResult EmployeeSearch(string name, int pageSize, int page)
    {
        var client = new EmployeeServiceClient();
        var searchResult = client.EmployeeSearch(name);
        var count = searchResult.Count();
        var employees = searchResult.Skip((page - 1) * pageSize).Take(pageSize).ToList();

        var viewModel = new EmployeeSearchViewModel
                            {
                                Employees = employees,
                                Size = count
                            };

        return Json(viewModel);
    }

OR

B) Make a $.getJSON to an HttpHandler, as described in Dave Wards http://encosia.com/use-asp-nets-httphandler-to-bridge-the-cross-domain-gap/

In the example above the WebClient.DownoadString() in the handler’s ProcessRequest method would take the following url string:

http://server/EmployeeService/EmployeeService.svc/Json/EmployeeSearch/searchstring

Both approaches allow my service to remain under windows auth and the clients have a couple means of accessing the service. The extra hop is irritating, but I try not to think about it.

And here’s the entire WCF serviceModel for reference:

<behaviors>
    <serviceBehaviors>
        <behavior name="EmployeeServiceBehavior">
            <serviceTimeouts transactionTimeout="01:00:00"/>
            <serviceMetadata httpGetEnabled="true"/>
            <serviceDebug includeExceptionDetailInFaults="true"/>
            <dataContractSerializer maxItemsInObjectGraph="2147483647"/>
        </behavior>
    </serviceBehaviors>

    <!-- we'd use this one if we wanted to ignore the 'd' wrapper around the json result ... we don't -->
    <endpointBehaviors>
        <!-- plain old XML -->
        <behavior name="poxBehavior">
            <webHttp helpEnabled="true" />
        </behavior>
        <!-- JSON -->
        <behavior name="jsonBehavior">
            <enableWebScript />
        </behavior>
    </endpointBehaviors>

</behaviors>

<bindings>
    <basicHttpBinding>
        <binding name="basicBinding"
                hostNameComparisonMode="StrongWildcard"
                receiveTimeout="00:10:00"
                sendTimeout="00:10:00"
                openTimeout="00:10:00"
                closeTimeout="00:10:00"
                maxReceivedMessageSize="2147483647"
                maxBufferSize="2147483647"
                maxBufferPoolSize="524288"
                transferMode="Buffered"
                messageEncoding="Text"
                textEncoding="utf-8"
                bypassProxyOnLocal="false"
                useDefaultWebProxy="true" >
            <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
            <!-- use the following for windows authentication -->
            <security mode="TransportCredentialOnly">
                <transport clientCredentialType="Windows" />
            </security>
        </binding>
    </basicHttpBinding>

    <webHttpBinding>
        <binding name="webBinding"
                receiveTimeout="00:10:00"
                sendTimeout="00:10:00"
                openTimeout="00:10:00"
                closeTimeout="00:10:00"
                maxReceivedMessageSize="2147483647"
                maxBufferSize="2147483647"
                maxBufferPoolSize="524288"
                bypassProxyOnLocal="false"
                useDefaultWebProxy="true"
                >
            <!--crossDomainScriptAccessEnabled="true"-->
            <!-- use the following for windows authentication -->
            <security mode="TransportCredentialOnly">
                <transport clientCredentialType="Windows" />
            </security>
        </binding>
    </webHttpBinding>

</bindings>

<services>
    <service name="EmployeeService.Wcf.EmployeeService" behaviorConfiguration="EmployeeServiceBehavior">
        <endpoint address="Soap" binding="basicHttpBinding" bindingConfiguration="basicBinding" contract="EmployeeService.Wcf.IEmployeeService"/>
        <endpoint address="Json" binding="webHttpBinding" bindingConfiguration="webBinding" behaviorConfiguration="poxBehavior" contract="EmployeeService.Wcf.IEmployeeService" />
    </service>
</services>

<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true"/>

One addition - the OperationContract for the above sample method is setup as follows in the ServiceContract:

    [OperationContract]
    [WebInvoke(Method = "GET", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, UriTemplate = "EmployeeSearch/{name}")]
    List<Employee> EmployeeSearch(string name);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文