【问题标题】:How to use HTTPS with WCF SessionMode.Required - simplest possible example如何将 HTTPS 与 WCF SessionMode.Required 一起使用 - 最简单的示例
【发布时间】:2014-09-23 18:10:01
【问题描述】:

更新 (8/7/2014) - 这个问题的解决方案是我需要添加一个派生自“UserNamePasswordValidator”的类并将其注册到 Web.Config。

我创建了一个简单的测试 WCF 服务和测试控制台客户端应用程序(代码见下文)。我正在使用 .NET 4.5.1。我已经在 StackOverflow 上搜索过重复的内容(找到了类似的帖子 herehere)——但是我觉得引用的帖子可能已经过时了,而且我觉得我的帖子范围更有限。

现在看例子:

解决方案当前使用会话(在 ITestService.cs 中):

[ServiceContract(SessionMode = SessionMode.Required)]

...并使用 wsHttpBinding(见下文 app.config 和 web.config)。

当我将它部署到服务器时,我可以通过使用 HTTPS 的 Web 浏览器成功访问它,如下所示:https://myserver.com/test/testservice.svc

但是,当我在客户端 app.config 中更改端点时:

http://localhost:20616/TestService.svc/TestService.svc

到:

https://myserver.com/test/testservice.svc

然后再次运行控制台应用程序,我收到错误:“提供的 URI 方案 'https' 无效;应为 'http'。参数名称:via”

我的问题是,在不更改 SessionMode.Required 的情况下,我需要做的最小更改是多少?

这是客户端控制台应用程序代码。请务必将“mycomputer\Matt”的 App.Config 值更改为适合您机器的正确值。

Program.cs

using System;

namespace TestClient
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Clear();
            Console.WriteLine("Attempting to log in...");
            try
            {
                TestServiceReference.TestServiceClient client = new TestServiceReference.TestServiceClient();

                bool loginSuccess = client.LogIn("admin", "password");
                if (loginSuccess)
                {
                    Console.WriteLine("Successfully logged in.");
                    string secretMessage = client.GetSecretData();
                    Console.WriteLine("Retrieved secret message: " + secretMessage);
                }
                else
                {
                    Console.WriteLine("Log in failed!");
                }
            }
            catch (Exception exc)
            {
                Console.WriteLine("Exception occurred: " + exc.Message);
            }
            Console.WriteLine("Press ENTER to quit.");
            Console.ReadLine();
        }
    }
}

App.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/>
    </startup>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_ITestService"/>
            </wsHttpBinding>
        </bindings>
        <client>
          <endpoint address="https://myserver.com/test/testservice.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ITestService" contract="TestServiceReference.ITestService" name="WSHttpBinding_ITestService">
            <identity>
              <userPrincipalName value="mycomputer\Matt"/>
            </identity>
          </endpoint>
            <!--<endpoint address="http://localhost:20616/TestService.svc/TestService.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ITestService" contract="TestServiceReference.ITestService" name="WSHttpBinding_ITestService">
                <identity>
                    <userPrincipalName value="mycomputer\Matt"/>
                </identity>
            </endpoint>-->
        </client>
    </system.serviceModel>
</configuration>

WCF 服务代码。
ITestService.cs:

using System.ServiceModel;

namespace WcfSessionsOverHttpsTest
{
    [ServiceContract(SessionMode = SessionMode.Required)]
    public interface ITestService
    {

        [OperationContract(IsInitiating = true)]
        bool LogIn(string username, string password);

        [OperationContract(IsInitiating = false, IsTerminating = true)]
        bool LogOut();

        [OperationContract(IsInitiating = false)]
        string GetSecretData();
    }
}

TestService.svc:

namespace WcfSessionsOverHttpsTest
{    
    public class TestService : ITestService
    {
        public bool IsAuthenticated { get; set; }
        bool ITestService.LogIn(string username, string password)
        {
            if (username == "admin" && password == "password")
            {
                IsAuthenticated = true;
                return true;
            }
            else
            {
                IsAuthenticated = false;
                return false;
            }
        }

        bool ITestService.LogOut()
        {
            IsAuthenticated = false;
            return true;
        }

        string ITestService.GetSecretData()
        {
            if (!IsAuthenticated)
            {
                throw new System.Security.Authentication.AuthenticationException("User has not logged in.");
            }
            else
            {
                string secretMessage = "The Red Sox are going to win the World Series in 2016";
                return secretMessage;
            }
        }
    }
}

Web.config:

<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5.1"/>
    <httpRuntime targetFramework="4.5"/>
  </system.web>
  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="wsHttpEndpointBinding" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" maxReceivedMessageSize="2147483647">
          <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
        </binding>
      </wsHttpBinding>
    </bindings>
    <services>
      <service name="WcfSessionsOverHttpsTest.TestService">
        <endpoint address="/TestService.svc" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" contract="WcfSessionsOverHttpsTest.ITestService"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
      <add binding="wsHttpBinding" scheme="http"/>
    </protocolMapping>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <directoryBrowse enabled="true"/>
  </system.webServer>
</configuration>

提前感谢您的帮助!

马特

【问题讨论】:

  • 至少要启用 HTTPS/SSL,您的绑定中至少需要 &lt;security mode="Transport"&gt;
  • 我将 添加到客户端和服务绑定中。现在我在客户端收到以下异常消息:“Contract 需要 Session,但 Binding 'WSHttpBinding' 不支持它或未正确配置以支持它。”
  • 添加: 到客户端和服务绑定导致在myserver.com/test/testservice.svc没有端点监听可以接受消息。这通常是由不正确的地址或 SOAP 操作引起的。有关更多详细信息,请参阅 InnerException(如果存在)。内部异常消息:远程服务器返回错误:(404)未找到。
  • "远程服务器返回错误:(404) Not Found。"显然是一个误导性的错误。 myserver.com/test/testservice.svc 仍然可以在浏览器中使用(注意:域显然不是 myserver.com,但我用它来隐藏我的实际域)。谢谢你。有什么想法吗?
  • 我对您的确切(所需)配置没有具体经验。我的建议是启用 WCF 跟踪并查看生成的日志。它们通常具有比异常消息更详细的诊断信息。

标签: c# wcf https wcf-binding


【解决方案1】:

这个问题的解决方案是我需要添加一个派生自“UserNamePasswordValidator”的类并在Web.Config中注册。

public class CustomUserNameValidator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        return;
    }
}

Web.config:

<behaviors>
  <serviceBehaviors>
    <behavior>
      <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
      <serviceMetadata httpsGetEnabled="true" />
      <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
      <serviceDebug includeExceptionDetailInFaults="true" />
      <serviceCredentials>
        <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="MyProgram.CustomUserNameValidator,MyProgram" />
      </serviceCredentials>
    </behavior>
  </serviceBehaviors>
</behaviors>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-06
    相关资源
    最近更新 更多