【问题标题】:HTTP WCF Service via HTTPS通过 HTTPS 的 HTTP WCF 服务
【发布时间】:2013-10-30 02:38:00
【问题描述】:

我有一个使用表单身份验证保护的 C# Web 应用程序项目。使用默认角色管理器管理各种页面的授权运行良好。

我最近向项目中添加了许多 WCF (*.svc) 服务,我使用 ASP.NET AJAX 从浏览器中使用 Javascript 调用这些服务(添加引用该服务的 ScriptManager)。这一切都可以使用 HTTP 正常工作。

我现在已经通过证书添加了 HTTPS 绑定到 IIS,并尝试通过 HTTPS 使用该应用程序;但是,引用该服务的页面在尝试加载 js 代理类 (service.svc/jsdebug) 时会引发“401 Unauthorized”错误。根据我收集到的信息,我需要更改 web.config 文件中的配置以使其正常工作,但我找不到任何可以使其正常工作的设置。我需要它可以通过 HTTP 协议(​​enableWebScript)访问,但通过 HTTPS。它还需要使用当前经过身份验证的 Forms 用户的身份。

任何关于在 web.config 中配置端点的一般建议也将不胜感激 - 或指向一个好的教程。谢谢

这是我目前的 web.config 文件的服务部分

  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="WsHttpBindingConfig">
          <security mode="Transport">
            <transport clientCredentialType="None" />
            <message clientCredentialType="UserName"/>
          </security>
        </binding>
      </wsHttpBinding>
      <webHttpBinding>
        <binding name="webHttp">
          <security mode="None">
          </security>
        </binding>
        <binding name="default"/>
      </webHttpBinding>
    </bindings>
    <behaviors>
      <endpointBehaviors>
        <behavior name="webScriptEnablingBehavior">
          <enableWebScript/>
        </behavior>
        <behavior name="scorelink.groups.Risk">
          <enableWebScript />
        </behavior>
        <behavior name="scorelink.tests.Benchmarks">
          <enableWebScript />
        </behavior>
        <behavior name="default">
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="DefaultBehaviours">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true" />
          <serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="MembershipProvider" membershipProviderName="SqlProvider"/>
          </serviceCredentials>
          <serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="SqlProvider" />
        </behavior>
        <behavior name="">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
    <services>
      <service name="scorelink.groups.Risk">
        <endpoint address="" behaviorConfiguration="scorelink.groups.Risk"
          binding="webHttpBinding" contract="scorelink.groups.Risk" />
      </service>
      <service name="scorelink.tests.Benchmarks" behaviorConfiguration="DefaultBehaviours">
        <endpoint address="" behaviorConfiguration="scorelink.tests.Benchmarks"
          binding="webHttpBinding" contract="scorelink.tests.Benchmarks" />
      </service>
      <service name="scorelink.services.user" behaviorConfiguration="DefaultBehaviours">
        <endpoint address="" binding="wsHttpBinding" behaviorConfiguration="default" bindingConfiguration="WsHttpBindingConfig" contract="scorelink.services.Iuser" />
        <endpoint address="http" binding="webHttpBinding" behaviorConfiguration="webScriptEnablingBehavior" bindingConfiguration="webHttp" contract="scorelink.services.Iuser" />
      </service>
    </services>
  </system.serviceModel>

这可能有点令人困惑,因为我尝试了很多东西。我目前只关注user.svc,但一旦它工作,我会将配置应用于所有服务。

编辑

我将配置更新为建议的配置,但现在出现以下错误:

The endpoint at 'https://localhost:44300/_assets/code/services/user.svc' does 
not have a Binding with the None MessageVersion. 
System.ServiceModel.Description.WebScriptEnablingBehavior' is only intended 
for use with WebHttpBinding or similar bindings.

我认为这是因为它使用了指定&lt;enableWebScript /&gt; 的端点行为。问题是如果我把它拿走,那么服务不会生成一个 javascript 代理类,所以我不能从 js 调用它。

编辑 2 这是 ASP.NET 为响应 EnableWebScript 标志而生成的 js 代理类的转储。可通过http://uri/service.svc/jsdebug访问:

Type.registerNamespace('scorelink.services');
scorelink.services.Iuser=function() {
scorelink.services.Iuser.initializeBase(this);
this._timeout = 0;
this._userContext = null;
this._succeeded = null;
this._failed = null;
}
scorelink.services.Iuser.prototype={
_get_path:function() {
 var p = this.get_path();
 if (p) return p;
 else return scorelink.services.Iuser._staticInstance.get_path();},
CreateUser:function(FirstName,LastName,Username,DateOfBirth,Roles,succeededCallback, failedCallback, userContext) {
/// <param name="FirstName" type="String">System.String</param>
/// <param name="LastName" type="String">System.String</param>
/// <param name="Username" type="String">System.String</param>
/// <param name="DateOfBirth" type="String">System.String</param>
/// <param name="Roles" type="Array">System.String[]</param>
/// <param name="succeededCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
return this._invoke(this._get_path(), 'CreateUser',false,{FirstName:FirstName,LastName:LastName,Username:Username,DateOfBirth:DateOfBirth,Roles:Roles},succeededCallback,failedCallback,userContext); },
UpdateUser:function(username,firstName,lastName,dateOfBirth,roles,succeededCallback, failedCallback, userContext) {
/// <param name="username" type="String">System.String</param>
/// <param name="firstName" type="String">System.String</param>
/// <param name="lastName" type="String">System.String</param>
/// <param name="dateOfBirth" type="String">System.String</param>
/// <param name="roles" type="Array">System.String[]</param>
/// <param name="succeededCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
return this._invoke(this._get_path(), 'UpdateUser',false,{username:username,firstName:firstName,lastName:lastName,dateOfBirth:dateOfBirth,roles:roles},succeededCallback,failedCallback,userContext); },
DeleteUser:function(Username,succeededCallback, failedCallback, userContext) {
/// <param name="Username" type="String">System.String</param>
/// <param name="succeededCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
return this._invoke(this._get_path(), 'DeleteUser',false,{Username:Username},succeededCallback,failedCallback,userContext); },
GetUserDetails:function(Username,succeededCallback, failedCallback, userContext) {
/// <param name="Username" type="String">System.String</param>
/// <param name="succeededCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
return this._invoke(this._get_path(), 'GetUserDetails',true,{Username:Username},succeededCallback,failedCallback,userContext); },
ChangePassword:function(oldPassword,newPassword,succeededCallback, failedCallback, userContext) {
/// <param name="oldPassword" type="String">System.String</param>
/// <param name="newPassword" type="String">System.String</param>
/// <param name="succeededCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
return this._invoke(this._get_path(), 'ChangePassword',false,{oldPassword:oldPassword,newPassword:newPassword},succeededCallback,failedCallback,userContext); },
ChangeLockoutCode:function(password,symbol1,symbol2,succeededCallback, failedCallback, userContext) {
/// <param name="password" type="String">System.String</param>
/// <param name="symbol1" type="Number">System.Int32</param>
/// <param name="symbol2" type="Number">System.Int32</param>
/// <param name="succeededCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
return this._invoke(this._get_path(), 'ChangeLockoutCode',false,{password:password,symbol1:symbol1,symbol2:symbol2},succeededCallback,failedCallback,userContext); }}
scorelink.services.Iuser.registerClass('scorelink.services.Iuser',Sys.Net.WebServiceProxy);
scorelink.services.Iuser._staticInstance = new scorelink.services.Iuser();
scorelink.services.Iuser.set_path = function(value) {
scorelink.services.Iuser._staticInstance.set_path(value); }
scorelink.services.Iuser.get_path = function() { 
/// <value type="String" mayBeNull="true">The service url.</value>
return scorelink.services.Iuser._staticInstance.get_path();}
scorelink.services.Iuser.set_timeout = function(value) {
scorelink.services.Iuser._staticInstance.set_timeout(value); }
scorelink.services.Iuser.get_timeout = function() { 
/// <value type="Number">The service timeout.</value>
return scorelink.services.Iuser._staticInstance.get_timeout(); }
scorelink.services.Iuser.set_defaultUserContext = function(value) { 
scorelink.services.Iuser._staticInstance.set_defaultUserContext(value); }
scorelink.services.Iuser.get_defaultUserContext = function() { 
/// <value mayBeNull="true">The service default user context.</value>
return scorelink.services.Iuser._staticInstance.get_defaultUserContext(); }
scorelink.services.Iuser.set_defaultSucceededCallback = function(value) { 
 scorelink.services.Iuser._staticInstance.set_defaultSucceededCallback(value); }
scorelink.services.Iuser.get_defaultSucceededCallback = function() { 
/// <value type="Function" mayBeNull="true">The service default succeeded callback.</value>
return scorelink.services.Iuser._staticInstance.get_defaultSucceededCallback(); }
scorelink.services.Iuser.set_defaultFailedCallback = function(value) { 
scorelink.services.Iuser._staticInstance.set_defaultFailedCallback(value); }
scorelink.services.Iuser.get_defaultFailedCallback = function() { 
/// <value type="Function" mayBeNull="true">The service default failed callback.</value>
return scorelink.services.Iuser._staticInstance.get_defaultFailedCallback(); }
scorelink.services.Iuser.set_enableJsonp = function(value) { scorelink.services.Iuser._staticInstance.set_enableJsonp(value); }
scorelink.services.Iuser.get_enableJsonp = function() { 
/// <value type="Boolean">Specifies whether the service supports JSONP for cross domain calling.</value>
return scorelink.services.Iuser._staticInstance.get_enableJsonp(); }
scorelink.services.Iuser.set_jsonpCallbackParameter = function(value) { scorelink.services.Iuser._staticInstance.set_jsonpCallbackParameter(value); }
scorelink.services.Iuser.get_jsonpCallbackParameter = function() { 
/// <value type="String">Specifies the parameter name that contains the callback function name for a JSONP request.</value>
return scorelink.services.Iuser._staticInstance.get_jsonpCallbackParameter(); }
scorelink.services.Iuser.set_path("http://localhost:5584/_assets/code/services/user.svc");
scorelink.services.Iuser.CreateUser= function(FirstName,LastName,Username,DateOfBirth,Roles,onSuccess,onFailed,userContext) {
/// <param name="FirstName" type="String">System.String</param>
/// <param name="LastName" type="String">System.String</param>
/// <param name="Username" type="String">System.String</param>
/// <param name="DateOfBirth" type="String">System.String</param>
/// <param name="Roles" type="Array">System.String[]</param>
/// <param name="succeededCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
scorelink.services.Iuser._staticInstance.CreateUser(FirstName,LastName,Username,DateOfBirth,Roles,onSuccess,onFailed,userContext); }
scorelink.services.Iuser.UpdateUser= function(username,firstName,lastName,dateOfBirth,roles,onSuccess,onFailed,userContext) {
/// <param name="username" type="String">System.String</param>
/// <param name="firstName" type="String">System.String</param>
/// <param name="lastName" type="String">System.String</param>
/// <param name="dateOfBirth" type="String">System.String</param>
/// <param name="roles" type="Array">System.String[]</param>
/// <param name="succeededCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
scorelink.services.Iuser._staticInstance.UpdateUser(username,firstName,lastName,dateOfBirth,roles,onSuccess,onFailed,userContext); }
scorelink.services.Iuser.DeleteUser= function(Username,onSuccess,onFailed,userContext) {
/// <param name="Username" type="String">System.String</param>
/// <param name="succeededCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
scorelink.services.Iuser._staticInstance.DeleteUser(Username,onSuccess,onFailed,userContext); }
scorelink.services.Iuser.GetUserDetails= function(Username,onSuccess,onFailed,userContext) {
/// <param name="Username" type="String">System.String</param>
/// <param name="succeededCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
scorelink.services.Iuser._staticInstance.GetUserDetails(Username,onSuccess,onFailed,userContext); }
scorelink.services.Iuser.ChangePassword= function(oldPassword,newPassword,onSuccess,onFailed,userContext) {
/// <param name="oldPassword" type="String">System.String</param>
/// <param name="newPassword" type="String">System.String</param>
/// <param name="succeededCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
scorelink.services.Iuser._staticInstance.ChangePassword(oldPassword,newPassword,onSuccess,onFailed,userContext); }
scorelink.services.Iuser.ChangeLockoutCode= function(password,symbol1,symbol2,onSuccess,onFailed,userContext) {
/// <param name="password" type="String">System.String</param>
/// <param name="symbol1" type="Number">System.Int32</param>
/// <param name="symbol2" type="Number">System.Int32</param>
/// <param name="succeededCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="failedCallback" type="Function" optional="true" mayBeNull="true"></param>
/// <param name="userContext" optional="true" mayBeNull="true"></param>
scorelink.services.Iuser._staticInstance.ChangeLockoutCode(password,symbol1,symbol2,onSuccess,onFailed,userContext); }
var gtc = Sys.Net.WebServiceProxy._generateTypedConstructor;
if (typeof(scorelink.services.UserDetails) === 'undefined') {
scorelink.services.UserDetails=gtc("UserDetails:http://schemas.datacontract.org/2004/07/scorelink.services");
scorelink.services.UserDetails.registerClass('scorelink.services.UserDetails');
}

【问题讨论】:

    标签: asp.net ajax wcf


    【解决方案1】:

    我认为你需要确认的事情很少:

    • 您有自签名证书。
    • 您已检查所需的 SSL。
    • 你有编辑绑定 -> 类型是 Https -> 端口是 443(默认 端口)。
    • 安全模式。
    • 端点地址="mex" binding="mexHttpsBinding" contract="IMetadataExchange"
    • 您正在访问服务的 Page.aspx.cs 中的一些自定义代码。

    【讨论】:

    • (1) 该站点在自签名证书下运行,公钥安装在本地计算机上。 (2) 我没有检查要求 SSL,因为我希望从 HTTP 和 HTTPS 访问它。 (3) 该网站使用自签名证书绑定到:80 和:443。 (4) 不确定“安全模式”是什么——您是指表单身份验证吗? (5) 我见过一些对 mex 绑定的引用,但它不会生成 js 代理类。 (6) 访问服务的代码是通过代理类的javascript。
    • 我的意思是安全模式是传输、消息等(根据需要)使用消息和客户端凭据类型=用户名。您正在使用哪种绑定?你能把你的js代理类放一块吗?
    • 请参阅最后关于代理的修正。谢谢
    【解决方案2】:

    根据对所提供信息的简要回顾,配置文件似乎没有正确定义安全性。比如下面的sn-p:

        <binding name="WsHttpBindingConfig">
          <security mode="Transport">
            <transport clientCredentialType="None" />
            <message clientCredentialType="UserName"/>
          </security>
    

    ... 应该看起来像:

      <wsHttpBinding>
            <binding name=" WsHttpBindingConfig">
                <security mode="TransportWithMessageCredential">
                    <message clientCredentialType="UserName"/>
                </security>
    

    以下链接提供了良好的背景信息:
    http://msdn.microsoft.com/en-us/library/ff648840.aspx
    http://www.codeproject.com/Articles/59927/WCF-Service-over-HTTPS-with-custom-username-and-pa

    问候,

    【讨论】:

    • 我已经阅读了这两个链接,它们很有趣,但并不能完全解决我的问题。第一个链接(MSDN atricle)导致我没有得到 js 代理类,因此该服务无法使用 - 该服务确实绑定到 https。第二个指南也很有趣,但也没有产生任何结果。两者都更侧重于使用指定的用户名和密码进行身份验证,而不是从 ASP.NET 传递已经经过身份验证的身份。想法?
    • 以下 SO Q/A 似乎解决了这个问题:*.com/questions/1531100/…
    • 感谢您花时间在这方面。我查看了 Q/A,这是一个类似的问题,但它正在使用 c# 使用服务 - 我正在使用 Javascript 使用它,问题就在于此:我没有可用的 c# 方法。
    最近更新 更多