簡體   English   中英

WCF身份驗證-使用自定義驗證程序的用戶名密碼-在我的機器上運行

[英]WCF Authentication - Username-Password using custom validator - Works on My Machine

我有一個WCF服務和一個客戶端,該客戶端使用自定義UserNamePasswordValidator進行身份驗證。

我使用由以下命令行創建的自簽名證書:

makecert -sr LocalMachine -ss My -a sha1 -n CN=SelfSignedCertificate -sky exchange -pe

從下面的客戶端在服務中調用方法在我的機器上可以正常工作:)但是,一旦將其部署到服務器上,我就會收到此錯誤消息: The request for security token could not be satisfied because authentication failed.

我可以瀏覽端點URL並查看該服務的WSDL。 我不確定,但是我記得我在本地計算機上的IIS中配置了一些匿名身份驗證,但是在服務器上看起來也是如此。

我的WCF服務使用以下配置托管在IIS 7.0中:

<system.serviceModel>
    <bindings>
        <wsHttpBinding>
            <binding name="secured">
                <security mode="Message">
                    <message clientCredentialType="UserName" />
                </security>
            </binding>
            <binding name="unsecured">
                <security mode="None" />
            </binding>
        </wsHttpBinding>
        <basicHttpBinding>
            <binding name="secured">
                <security mode="TransportWithMessageCredential">
                    <message clientCredentialType="UserName" />
                </security>
            </binding>
            <binding name="unsecured">
                <security mode="None" />
            </binding>
        </basicHttpBinding>
        <webHttpBinding>
            <binding name="unsecured">
                <security mode="None" />
            </binding>
        </webHttpBinding>
    </bindings>
    <services>
        <service name="Milkshake.Admin.Services.AdminService" behaviorConfiguration="CustomValidator">
            <endpoint address="" binding="wsHttpBinding" contract="Milkshake.Admin.Model.ServiceContracts.IAdminService" bindingConfiguration="secured" />
        </service>
        <service name="Milkshake.Admin.Services.DeploymentService">
            <endpoint address="" binding="wsHttpBinding" contract="Milkshake.Admin.Model.ServiceContracts.IDeploymentService"/>
        </service>
        <service name="Milkshake.Admin.Services.LogService" behaviorConfiguration="CustomValidator">
            <endpoint address="" binding="wsHttpBinding" contract="Milkshake.Core.Logging.ILogService" bindingConfiguration="secured" />
        </service>
        <service name="Milkshake.Admin.Services.MailService">
            <endpoint address="" binding="wsHttpBinding" contract="Milkshake.Admin.Model.ServiceContracts.IMailService"/>
        </service>
    </services>
    <behaviors>
        <serviceBehaviors>
            <behavior name="CustomValidator">
                <serviceMetadata httpGetEnabled="true" />
                <serviceCredentials>
                    <serviceCertificate findValue="SelfSignedCertificate" x509FindType="FindBySubjectName" />
                    <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Milkshake.Admin.Services.MilkshakeCredentialValidator, Milkshake.Admin.Services" />
                    <clientCertificate>
                        <authentication certificateValidationMode="None" />
                    </clientCertificate>
                </serviceCredentials>
                <serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="true" />
            </behavior>
        </serviceBehaviors>

        <endpointBehaviors>
            <behavior name="json">
                <enableWebScript />
            </behavior>

            <behavior name="xml">
                <webHttp defaultOutgoingResponseFormat="Xml" defaultBodyStyle="Wrapped" />
            </behavior>
        </endpointBehaviors>
    </behaviors>
</system.serviceModel>

客戶端配置如下所示:

<system.serviceModel>
    <client>
        <endpoint address="http://server-url/LogService.svc" binding="wsHttpBinding" contract="Milkshake.Core.Logging.ILogService">
            <identity>
                <dns value="SelfSignedCertificate" />
            </identity>
        </endpoint>
    </client>
</system.serviceModel>

我的自定義驗證器是這樣的:

using System;
using System.IdentityModel.Selectors;
using System.ServiceModel;

namespace Milkshake.Admin.Services
{
    /// <summary>
    /// WCF Service validator for Milkshake.
    /// </summary>
    public class MilkshakeCredentialValidator : UserNamePasswordValidator
    {
        /// <summary>
        /// When overridden in a derived class, validates the specified username and password.
        /// </summary>
        /// <param name="userName">The username to validate.</param>
        /// <param name="password">The password to validate.</param>
        public override void Validate(string userName, string password)
        {
            if (String.IsNullOrWhiteSpace(userName) || String.IsNullOrWhiteSpace(password))
            {
                throw new ArgumentNullException();
            }

            if (userName.Equals("martin") && password.Equals("normark"))
            {
                return;
            }

            FaultCode fc = new FaultCode("ValidationFailed");
            FaultReason fr = new FaultReason("Good reason");

            throw new FaultException(fr, fc);
        }
    }
}

我的服務客戶端如下所示:

using System;
using System.ServiceModel;
using System.ServiceModel.Security;
using Milkshake.Core.Logging;

namespace Milkshake.Admin.ServiceClients.Logging
{
    /// <summary>
    /// WCF Service Client implementation of the <see cref="ILogService"/> contract.
    /// </summary>
    public class LogServiceClient : ILogService
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="LogServiceClient"/> class.
        /// </summary>
        public LogServiceClient()
        {
            var factory = new ChannelFactory<ILogService>(String.Empty);
            factory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
            factory.Credentials.UserName.UserName = "martin";
            factory.Credentials.UserName.Password = "normark";

            var binding = factory.Endpoint.Binding as WSHttpBinding;

            if (binding != null)
            {
                binding.Security.Mode = SecurityMode.Message;
                binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
            }

            this.AdminLogService = factory.CreateChannel();
        }

        /// <summary>
        /// Gets or sets the admin log service.
        /// </summary>
        /// <value>The admin log service.</value>
        private ILogService AdminLogService { get; set; }

        #region ILogService Members

        /// <summary>
        /// Logs the error simple.
        /// </summary>
        /// <param name="applicationInstanceId">The application instance id.</param>
        /// <param name="logDate">The log date.</param>
        /// <param name="exceptionMessage">The exception message.</param>
        /// <param name="description">The description.</param>
        /// <param name="severity">The severity.</param>
        /// <param name="userAgent">The user agent.</param>
        /// <param name="source">The source.</param>
        public void LogErrorSimple(int applicationInstanceId, DateTime logDate, string exceptionMessage, string description, Severity severity, string userAgent, string source)
        {
            this.AdminLogService.LogErrorSimple(applicationInstanceId, logDate, exceptionMessage, description, severity, userAgent, source);
        }

        /// <summary>
        /// Logs the error advanced.
        /// </summary>
        /// <param name="applicationInstanceId">The application instance id.</param>
        /// <param name="logDate">The log date.</param>
        /// <param name="exceptionType">Type of the exception.</param>
        /// <param name="exceptionCode">The exception code.</param>
        /// <param name="exceptionMessage">The exception message.</param>
        /// <param name="stackTrace">The stack trace.</param>
        /// <param name="caller">The caller.</param>
        /// <param name="location">The location.</param>
        /// <param name="source">The source (A service, app etc).</param>
        /// <param name="description">The description.</param>
        /// <param name="severity">The severity.</param>
        /// <param name="username">The username.</param>
        /// <param name="userAgent">The user agent.</param>
        public void LogErrorAdvanced(int applicationInstanceId, DateTime logDate, string exceptionType, string exceptionCode, string exceptionMessage, string stackTrace, string caller, string location, string source, string description, Severity severity, string username, string userAgent)
        {
            this.AdminLogService.LogErrorAdvanced(applicationInstanceId, logDate, exceptionType, exceptionCode, exceptionMessage, stackTrace, caller, location, source, description, severity, userAgent, userAgent);
        }

        /// <summary>
        /// Logs the behavior with data.
        /// </summary>
        /// <param name="applicationInstanceId">The application instance id.</param>
        /// <param name="action">The action.</param>
        /// <param name="logDate">The log date.</param>
        /// <param name="userAgent">The user agent.</param>
        /// <param name="behaviorData">The behavior data.</param>
        /// <param name="source">The source.</param>
        public void LogBehaviorWithData(int applicationInstanceId, string action, DateTime logDate, string userAgent, string behaviorData, string source)
        {
            this.AdminLogService.LogBehaviorWithData(applicationInstanceId, action, logDate, userAgent, behaviorData, source);
        }

        /// <summary>
        /// Logs the behavior.
        /// </summary>
        /// <param name="applicationInstanceId">The application instance id.</param>
        /// <param name="action">The action.</param>
        /// <param name="logDate">The log date.</param>
        /// <param name="userAgent">The user agent.</param>
        /// <param name="source">The source.</param>
        public void LogBehavior(int applicationInstanceId, string action, DateTime logDate, string userAgent, string source)
        {
            this.AdminLogService.LogBehavior(applicationInstanceId, action, logDate, userAgent, source);
        }

        #endregion
    }
}

我還將UserNamePasswordValidator與使用makecert生成的證書一起使用。

可以使用WcfSvcHost而不是IIS,以確保它可以成功啟動。 我建議這樣做的原因是證書的鏈構建可能失敗。 您可以使用一個設置來禁用鏈構建。 更新:我認為您已經使用CertificateValidationMode =“ none”進行了此操作)

我要注意的另一件事是,並非您的所有服務定義都指定了behaviourConfiguration。 這有點像山毛櫸,因為在更新服務引用時,有時VS會將其刪除。

您提到的異常是最內部異常的消息嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM