使用自定义身份验证保护WCF服务端点

7
我想保护WCF服务的一些端点,但我不知道您是否可以保护某些端点而不是其他端点。以下是剥离后的WCF服务(自托管)。同样的WCF还提供CA策略文件。如果我保护此WCF服务或其某些端点,则CA策略部分不得要求我输入用户名密码。策略文件必须始终可访问。这也可能吗?
我找到了很多WCF自定义博客/文章。有很多方法可以进行安全性保护。我想做的就是可以使用用户名/密码保护某些端点,但是凭据在像Fiddler这样的工具中不可见。数据在这种情况下可以可见。
我已经实现了一个Customvalidator,但是app.config文件也很重要来定义事物。而我对此并不很擅长。
namespace WindowsFormsApplication11
{
    public partial class Form1 : Form
    {
        public ServiceHost _host = null;

        public Form1()
        {
            InitializeComponent();
        }      

        private void button1_Click(object sender, EventArgs e)
        {
            // Create a ServiceHost for the CalculatorService type and 
            // provide the base address.
            _host = new ServiceHost(typeof(WmsStatService));
            _host.AddServiceEndpoint(typeof(IPolicyProvider), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());

            _host.Open();
        }
    }

    // Define a service contract.
    [ServiceContract(Namespace = "http://WindowsFormsApplication11")]
    public interface IWmsStat
    {
        [OperationContract]
        string getConnectedViewers(string channelName);
        [OperationContract]
        string sayHello(string name);
    }

    [ServiceContract]
    public interface IPolicyProvider
    {
        [OperationContract, WebGet(UriTemplate = "/ClientAccessPolicy.xml")]
        Stream ProvidePolicy();
    }
    //[DataContract]
    public class Ads
    {
       // [DataMember]
        public string AdFileName { get; set; }
        //[DataMember]
        public string AdDestenationUrl { get; set; }
        public string ConnectedUserIP { get; set; }
    }
    //
    public class CustomValidator : UserNamePasswordValidator
    {
        public override void Validate(string userName, string password)
        {
            if(null == userName || null == password)
            {
                    throw new ArgumentNullException();
            }
            if(userName == "Oguz" && password == "2009")
            {
                return;
            }
            FaultCode fc =  new FaultCode("ValidationFailed");
            FaultReason fr = new FaultReason("Good reason");
            throw new FaultException(fr,fc);
        }
    }
    //

    public class WmsStatService : IWmsStat, IPolicyProvider
    {
        public string sayHello(string name)
        {
            return "hello there " + name + " nice to meet you!";
        }

        public Stream ProvidePolicy()
        {
            WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
            return new MemoryStream(File.ReadAllBytes("ClientAccessPolicy.xml"), false);
        }

        public string getConnectedViewers(string channelname)
        {
            // do stuff
            return null;
        }
    }
}

app.config配置文件不能正常工作。我想为一个端点添加自定义身份验证,但是完全不知道如何操作。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="WindowsFormsApplication11.WmsStatService" behaviorConfiguration="mex">
        <host>
          <baseAddresses>
            <add baseAddress="http://192.168.0.199:87" />
          </baseAddresses>
        </host>        
        <endpoint address="http://192.168.0.199:87/Test" binding="basicHttpBinding" bindingConfiguration="" contract="WindowsFormsApplication11.IWmsStat" behaviorConfiguration="MyServiceBehavior" />
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>

    <!--<bindings>
      <wsHttpBinding>      
        <binding name="wshttp">
          <security mode="Message">
            <message clientCredentialType="UserName" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>-->

    <behaviors>
      <serviceBehaviors>
        <behavior name="mex">
          <serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
        </behavior>
        <behavior name="MyServiceBehavior">
          <serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WindowsFormsApplication11.CustomValidator, CustomValidator" />
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>      
    </behaviors>
  </system.serviceModel>
</configuration>
2个回答

17

我想要保护 WCF 服务的某些端点,不知道是否可以保护一些端点而不保护另一些端点。

可以 - 您只需要创建两个不同的绑定配置,并在需要保护的端点上使用其中一个,另一个则用于其他端点:

<bindings>
  <basicHttpBinding>
    <binding name="secured">
      <security mode="Message">
        <message ...... />
      </security>
    </binding>
    <binding name="unsecured">
      <security mode="None" />
    </binding>
  </basicHttpBinding>
</bindings>
<services>
  <service name="WindowsFormsApplication11.WmsStatService" behaviorConfiguration="mex">
    <host>
      <baseAddresses>
        <add baseAddress="http://192.168.0.199:87" />
      </baseAddresses>
    </host>        

    <endpoint address="/Secured/Test" 
              binding="basicHttpBinding" bindingConfiguration="secured" 
              contract="WindowsFormsApplication11.IWmsStat" 
              behaviorConfiguration="MyServiceBehavior" />

    <endpoint address="/Unsecured/Test" 
              binding="basicHttpBinding" bindingConfiguration="unsecured" 
              contract="WindowsFormsApplication11.IWmsStat" 
              behaviorConfiguration="MyServiceBehavior" />

    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
  </service>
</services>

Marc

PS:不确定是否只是您发布内容不再最新的问题 - 您是否注意到您有两个单独的行为配置:

<behaviors>
    <serviceBehaviors>
      <behavior name="mex">
        <serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
      </behavior>
      <behavior name="MyServiceBehavior">
        <serviceCredentials>
          <userNameAuthentication 
               userNamePasswordValidationMode="Custom" 
                customUserNamePasswordValidatorType="WindowsFormsApplication11.CustomValidator, CustomValidator" />
        </serviceCredentials>
      </behavior>
   </serviceBehaviors>      
</behaviors>

你的服务只引用了“mex”行为吗?这意味着,你的服务确实使用了<serviceMetadata>行为,但没有使用<serviceCredentials>行为!

你需要将它们合并成一个,然后引用该行为:

<behaviors>
    <serviceBehaviors>
      <behavior name="Default">
        <serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
        <serviceCredentials>
          <userNameAuthentication 
               userNamePasswordValidationMode="Custom" 
                customUserNamePasswordValidatorType="WindowsFormsApplication11.CustomValidator, CustomValidator" />
        </serviceCredentials>
      </behavior>
   </serviceBehaviors>      
</behaviors>
<services>
    <service name="...." behaviorConfiguration="Default" 

Marc

->

马克


我将其更改为WindowsFormsAppiication11。这是一个在Windows Forms上自托管的WCF服务。当我将其更改为我所说的内容后,错误消失了,但出现了另一个问题:(“http://192.168.0.199:87/Test”处的ChannelDispatcher与合同““IWmsStat””无法打开其IChannelListener。 - Shift
你需要学习WCF安全的基础知识 - 可以查看以下资源:http://msdn.microsoft.com/en-us/library/ms731925.aspx 和 http://msdn.microsoft.com/en-us/magazine/cc163570.aspx,以便更好地掌握WCF中安全性能够和不能够做到的事情。 - marc_s
不不不 - 如果您使用服务证书,绝对不需要客户端证书!您完全误解了这一点!阅读基础知识,再次阅读,直到您理解为止 - 安全并不容易,但在任何其他技术中也不容易..... - marc_s
Silverlight目前仅支持basicHttpBinding,所以请立即忘记wsHttp - 很不幸 :-( - marc_s
1
同意 - 我也给你+1,因为你非常有耐心和乐于助人! - Shaul Behr
显示剩余8条评论

2
如果您想要保护整个消息,则传输安全模式是一个好的选择。如果您只想加密/签名您的头部,消息安全模式允许这样做,但您需要使用wsHttpBinding。您还可以考虑使用摘要来保护凭据。
至于您的示例,我认为您的注释部分应该像这样:
<bindings>
  <basicHttpBinding>
          <binding name="secure">
      <security mode="Transport">
        <transport clientCredentialType="Basic" />
      </security>
    </binding>
  </basicHttpBinding>
</bindings>

您还需要更新端点声明:

<endpoint 
     address="https://192.168.0.199:87/Test" 
     binding="basicHttpBinding" bindingConfiguration="secure" 
     contract="WindowsFormsApplication11.IWmsStat" />

在传输安全模式下,您将无法使用纯HTTP。


使用该配置时,我遇到了以下错误:没有名为'MyServiceBehavior'的终结点行为。 - Shift
我不想使用https,所以我选择了消息安全模式。 - Shift
将behaviorConfiguration="CalculatorServiceBehavior"属性从move标签移动到service标签中。 - Dmitry Ornatsky
在服务标记上,behaviorConfiguration="mex",如果我更改它,会影响到我的其他代码吗? - Shift
将这两个行为合并成一个,并引用它。 - Dmitry Ornatsky
好的,我改了一些东西但是验证器报错了。无法加载文件或程序集“CustomValidator”或其某个依赖项。系统找不到指定的文件。 - Shift

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接