C# 在App.config中设置WCF客户端凭据

C# 在App.config中设置WCF客户端凭据,c#,.net,vb.net,wcf,configuration,C#,.net,Vb.net,Wcf,Configuration,是否可以在App.config中为WCF设置clientcredentials 我希望避免这样做: Using svc As New MyServiceClient svc.ClientCredentials.UserName.UserName = "login" svc.ClientCredentials.UserName.Password = "pw" ... End Using 相反,登录名和密码应该是配置的一部分。据我所知,使用serviceModel配置部分是不可能的,

是否可以在App.config中为WCF设置clientcredentials

我希望避免这样做:

Using svc As New MyServiceClient
  svc.ClientCredentials.UserName.UserName = "login"
  svc.ClientCredentials.UserName.Password = "pw"

  ...
End Using

相反,登录名和密码应该是配置的一部分。

据我所知,使用serviceModel配置部分是不可能的,因为它会造成安全漏洞。 但您可以为这些值创建常规appSettings,并在代码中使用它们:

svc.ClientCredentials.UserName.UserName = ConfigurationManager.AppSettings("...")

不过,我建议不要使用这种方法,除非您加密配置文件。

您可以尝试继承(处理默认配置部分)并添加对用户名和密码的支持。然后,您可以在配置文件中将此元素注册为行为扩展名,并使用它来代替公共配置部分。

扩展Ladislav Mrnka的答案,您可能会发现此实现非常有用:

public class UserNameClientCredentials : ClientCredentialsElement
{
    private ConfigurationPropertyCollection properties;

    public override Type BehaviorType
    {
        get { return typeof (ClientCredentials); }
    }

    /// <summary>
    /// Username (required)
    /// </summary>
    public string UserName
    {
        get { return (string) base["userName"]; }
        set { base["userName"] = value; }
    }

    /// <summary>
    /// Password (optional)
    /// </summary>
    public string Password
    {
        get { return (string) base["password"]; }
        set { base["password"] = value; }
    }

    protected override ConfigurationPropertyCollection Properties
    {
        get
        {
            if (properties == null)
            {
                ConfigurationPropertyCollection baseProps = base.Properties;
                baseProps.Add(new ConfigurationProperty(
                                  "userName",
                                  typeof (String),
                                  null,
                                  null,
                                  new StringValidator(1),
                                  ConfigurationPropertyOptions.IsRequired));
                baseProps.Add(new ConfigurationProperty(
                                  "password",
                                  typeof (String),
                                  ""));
                properties = baseProps;
            }
            return properties;
        }
    }

    protected override object CreateBehavior()
    {
        var creds = (ClientCredentials) base.CreateBehavior();
        creds.UserName.UserName = UserName;
        if (Password != null) creds.UserName.Password = Password;
        ApplyConfiguration(creds);
        return creds;
    }
}
公共类UserNameClientCredentials:ClientCredentialsElement { 私有配置属性集合属性; 公共重写类型BehaviorType { 获取{return typeof(ClientCredentials);} } /// ///用户名(必填) /// 公共字符串用户名 { 获取{return(string)base[“userName”];} 设置{base[“userName”]=value;} } /// ///密码(可选) /// 公共字符串密码 { 获取{return(string)base[“password”];} 设置{base[“password”]=value;} } 受保护的覆盖配置属性集合属性 { 得到 { 如果(属性==null) { ConfigurationPropertyCollection baseProps=base.Properties; baseProps.Add(新配置属性( “用户名”, 类型(字符串), 无效的 无效的 新的StringValidator(1), ConfigurationPropertyOptions.IsRequired)); baseProps.Add(新配置属性( “密码”, 类型(字符串), "")); 属性=基本道具; } 归还财产; } } 受保护的重写对象CreateBehavior() { var creds=(ClientCredentials)base.CreateBehavior(); creds.UserName.UserName=用户名; 如果(Password!=null)creds.UserName.Password=Password; 应用程序配置(creds); 回信; } } 之后,您需要使用以下内容注册此自定义实现

<system.serviceModel>
  <extensions>
    <behaviorExtensions>
      <add name="UserNameClientCredentials" type="MyNamespace.UserNameClientCredentials, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </behaviorExtensions>
  </extensions>
...

...

这就是我为了让新的身份验证生效所做的

在此基础上进一步扩展的是如何使用customBehavior实现

public class UserNameClientCredentialsElement : ClientCredentialsElement
{ // class renamed only to follow the configuration pattern
   ... // using Mormegil's implementation
}
之后,您需要:

  • 注册behaviorExtension
  • 使用配置扩展名定义新的behaviorConfig。(这是一个棘手的部分,关于如何做到这一点的报道很少。)
  • 将配置应用于端点
  • 使用类似于:

    <system.serviceModel>
      <client><!--(3)-->
        <endpoint ...YourEndpointConfig... behaviorConfiguration="UserNamePasswordBehavior" />
      </client>
      <behaviors><!--(2)-->
        <endpointBehaviors>
          <behavior name="UserNamePasswordBehavior">
            <userNameClientCredentials userName="skroob" password="12345" />
            <!--Visual Studio will give you warning squiggly on <userNameClientCredentials>
                saying that "The element 'behavior' has invalid child element" 
                but will work at runtime.-->
          </behavior>
        </endpointBehaviors>
      </behaviors>
      <extensions><!--(1)-->
        <behaviorExtensions>
          <add name="userNameClientCredentials" type="MyNamespace.UserNameClientCredentialsElement, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
        </behaviorExtensions>
      </extensions>
      ...
    </system.serviceModel>
    
    
    ...
    
    谢谢。但是在AppSettings中存储凭据仍然需要我以编程方式设置这些值。我确信这可能是一个安全问题,但我看不出有什么区别:人们无论如何都会将登录/pw存储在某个地方——为什么不将其与WCF配置的其余部分一起存储呢??)正如你所说,这与安全有关。为用户提供以明文指定密码的方法是一个明显的安全漏洞。现在,如果开发人员决定使用我提供的代码对其进行旁路,他将意识到自己的错误。他不会说“嘿,微软,是你的错,你说把它放在WCF配置中没问题。”谢谢,这看起来是一个非常简洁的实现。总有一天我会试试的