在WCF中,自定义Authentication,Validate方法,抛出错误异常时如何在不停止服务的情况下处理异常?

Posted

技术标签:

【中文标题】在WCF中,自定义Authentication,Validate方法,抛出错误异常时如何在不停止服务的情况下处理异常?【英文标题】:In WCF, custom Authentication, the Validate method, how to handle exception without stopping service when throwing fault exception? 【发布时间】:2020-12-25 00:30:23 【问题描述】:

我有一个使用自定义身份验证的 WCF 服务,继承自 UserNamePasswordValidator, 而且,我注意到如果用户未进行身份验证/无效,我必须抛出错误异常才能使身份验证工作。

我的问题是我只想为客户端而不是服务器抛出异常。因为,我不想停止服务器。

我搜索了答案,找到了 FaultContract,但没有用。

这是我的代码

 public override void Validate(string userName, string password)
    
        if (HandleAuthentication(userName, password))
        
            // Authenticated
            return;
        
        else
        
            throw new FaultException(
                "Invalid username or password.",
                new FaultCode("AUTHENTICATION_FAILURE"));
                
        
        
    

【问题讨论】:

【参考方案1】:

这是我的演示:

Service.cs:

using System;
using System.IdentityModel.Selectors;
using System.Security.Principal;
using System.ServiceModel;

namespace Microsoft.Samples.UserNamePasswordValidator

    // Define a service contract.
    [ServiceContract(Namespace="http://Microsoft.Samples.UserNamePasswordValidator")]
    public interface ICalculator
    
        [OperationContract]
        double Add(double n1, double n2);
        [OperationContract]
        double Subtract(double n1, double n2);
        [OperationContract]
        double Multiply(double n1, double n2);
        [OperationContract]
        double Divide(double n1, double n2);
    

    // Service class which implements the service contract.
    // Added code to write output to the console window
    [ServiceBehavior(IncludeExceptionDetailInFaults=true)]
    
    public class CalculatorService : ICalculator
    
        public double Add(double n1, double n2)
        
            double result = n1 + n2;
            Console.WriteLine("Received Add(0,1)", n1, n2);
            Console.WriteLine("Return: 0", result);
            return result;
        


        public double Subtract(double n1, double n2)
        
            double result = n1 - n2;
            Console.WriteLine("Received Subtract(0,1)", n1, n2);
            Console.WriteLine("Return: 0", result);
            return result;
        


        public double Multiply(double n1, double n2)
        
            double result = n1 * n2;
            Console.WriteLine("Received Multiply(0,1)", n1, n2);
            Console.WriteLine("Return: 0", result);
            return result;
        

        
        public double Divide(double n1, double n2)
        
            double result = n1 / n2;
            Console.WriteLine("Received Divide(0,1)", n1, n2);
            Console.WriteLine("Return: 0", result);
            return result;
        

        public class CustomUserNameValidator : System.IdentityModel.Selectors.UserNamePasswordValidator
        
            // This method validates users. It allows in two users, test1 and test2 
            // with passwords 1tset and 2tset respectively.
            // This code is for illustration purposes only and 
            // MUST NOT be used in a production environment because it is NOT secure.   
            public override void Validate(string userName, string password)
            
                if (null == userName || null == password)
                
                    throw new ArgumentNullException();
                

                if (!(userName == "test1" && password == "1tset") && !(userName == "test2" && password == "2tset"))
                
                    throw new FaultException("Unknown Username or Incorrect Password");
                
            
        
 
        // Host the service within this EXE console application.
        public static void Main()
        
            // Create a ServiceHost for the CalculatorService type and provide the base address.
            using (ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService)))
            
                // Open the ServiceHostBase to create listeners and start listening for messages.
                serviceHost.Open();
                
                // The service can now be accessed.
                Console.WriteLine("The service is ready.");
        Console.WriteLine("The service is running in the following account: 0", WindowsIdentity.GetCurrent().Name);
                Console.WriteLine("Press <ENTER> to terminate service.");
                Console.WriteLine();
                Console.ReadLine();
            
        
    

App.config:

<?xml version="1.0"?>
<!--
   Copyright (c) Microsoft Corporation.  All rights reserved.
-->
<configuration>

  <system.serviceModel>
    <services>
      <service name="Microsoft.Samples.UserNamePasswordValidator.CalculatorService" behaviorConfiguration="CalculatorServiceBehavior">
        <host>
          <baseAddresses>
            <!-- configure base address for host -->
            <add baseAddress="http://localhost:8001/servicemodelsamples/service"/>
          </baseAddresses>
        </host>
        <!-- use base address provided by host, provide one endpoint -->
        <endpoint address="username" binding="wsHttpBinding" bindingConfiguration="Binding1" contract="Microsoft.Samples.UserNamePasswordValidator.ICalculator"/>
      </service>
    </services>

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

    <behaviors>
      <serviceBehaviors>
        <behavior name="CalculatorServiceBehavior" includeExceptionDetailInFaults="True">
          <serviceCredentials>
            <!-- 
            The serviceCredentials behavior allows one to specify a custom validator for username/password combinations.                  
            -->
            <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Microsoft.Samples.UserNamePasswordValidator.CalculatorService+CustomUserNameValidator, service"/>
            <!-- 
            The serviceCredentials behavior allows one to define a service certificate.
            A service certificate is used by a client to authenticate the service and provide message protection.
            This configuration references the "localhost" certificate installed during the setup instructions.
            -->
            <serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName"/>
          </serviceCredentials>        
        </behavior>
      </serviceBehaviors>
    </behaviors>
    
  </system.serviceModel>

<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>

如果问题仍然存在,请随时告诉我。

这是一个演示:

如果你需要这个例子,你可以在下面的链接中得到它:

https://www.microsoft.com/en-us/download/details.aspx?id=21459

【讨论】:

我尝试创建新的控制台应用程序并重新创建它,但出现错误,例如 ServiceHost 不存在,我需要检查 nuget。我检查了命名空间的 nuget,但结果我已经下载了包。你能给我演示应用程序,看看这是否可行。谢谢。

以上是关于在WCF中,自定义Authentication,Validate方法,抛出错误异常时如何在不停止服务的情况下处理异常?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 wcf 中添加自定义肥皂标题?

如何在 IIS 中将 WCF 与 basichttpbinding only 、 SSL 和 Basic Authentication 一起使用?

在 WCF 中添加自定义标头? [复制]

Windows authentication for WCF web services error

如何创建一个自定义的Authentication Provider

在 wcf 中添加用于安全身份验证的自定义标头