带有 Windows 身份验证的 WCF jsonP - 可能吗?

Posted

技术标签:

【中文标题】带有 Windows 身份验证的 WCF jsonP - 可能吗?【英文标题】:WCF jsonP with Windows Authentication - Possible? 【发布时间】:2011-12-15 17:16:32 【问题描述】:

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

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

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

我的网络配置如下

<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>

【问题讨论】:

您可以编写自定义绑定和编码器来做到这一点。 jeremybranham.wordpress.com/2011/11/11/… 【参考方案1】:

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

我能够使用从跨域客户端访问的经过 Windows 身份验证的 WCF 服务(托管在 IIs 7.5 中)的唯一方法是让客户端通过代理进行调用。有一个额外的跳回到代理,但现在我不再依赖 JSONP。该服务设置有两个端点,soap 和 json - 我将整个 serviceModel 贴在底部以供参考。

所以客户端应用程序(都是 .NET Web 应用程序):

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

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) 为 HttpHandler 创建一个 $.getJSON,如 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);

【讨论】:

以上是关于带有 Windows 身份验证的 WCF jsonP - 可能吗?的主要内容,如果未能解决你的问题,请参考以下文章

创建 WCF 休息服务以接受 SAML 并对 Windows 用户进行身份验证

使用 Silverlight 5、IIS 7.5 对 WCF 服务进行 Windows 身份验证

.net 核心中调用 wcf 的身份验证方案

带有用户名身份验证的 WCF 中的异常

WCF 客户端证书验证 + Windows 身份验证

带有客户端证书身份验证的 Wcf 不适用于 soapui