如何从自定义授权策略向客户端发送有意义的错误

时间:2018-02-06 17:12:20

标签: c# .net wcf error-handling authorization

我为WCF服务实现了自定义IAuthorizationPolicy。它工作正常,除非授权失败,客户端收到无意义的错误。

如果我只是return false方法中的Evaluate,客户端就会收到此信息:

  

System.ServiceModel.FaultException :'由于内部错误,服务器无法处理请求。有关错误的更多信息,请在服务器上启用IncludeExceptionDetailInFaults(来自ServiceBehaviorAttribute或配置行为),以便将异常信息发送回客户端,或者根据Microsoft .NET Framework SDK文档打开跟踪,检查服务器跟踪日志。'

如果我抛出FaultException<MyCustomErrorDetails>,客户端会收到:

  

System.ServiceModel.CommunicationException:&#39;接收到http://localhost:9034/Service1.svc的HTTP响应时发生错误。这可能是由于服务端点绑定不使用HTTP协议。这也可能是由于服务器中止HTTP请求上下文(可能是由于服务关闭)。有关详细信息,请参阅服务器日志。&#39;

哪个更没用。

如何向客户返回有意义的错误,例如&#34;授权失败&#34;?

1 个答案:

答案 0 :(得分:1)

在WCF服务中启用详细的错误消息可以通过行为配置来完成:

  <serviceBehaviors>
    <behavior>
      <serviceDebug includeExceptionDetailInFaults="true"/>      
    </behavior>
  </serviceBehaviors>

通常,您将创建一个包含故障信息的类型,例如:

[DataContract]
public class SecurityFault
{
    private string operation;
    private string problemType;

    [DataMember]
    public string Operation
    {
        get { return operation; }
        set { operation = value; }
    }

    [DataMember]
    public string ProblemType
    {
        get { return problemType; }
        set { problemType = value; }
    }
}

在服务合同中,您需要使用故障合同来装饰操作,如下所示:

[ServiceContract]
public interface IService
{
    [OperationContract]
    [FaultContract(typeof(SecurityFault))]
    int Divide(int number1, int number2);
}

在这种情况下,您将在授权策略中抛出异常,例如:

public class AuthorizationAlwaysFails : IAuthorizationPolicy
{
    public ClaimSet Issuer => throw new NotImplementedException();

    public string Id => Guid.NewGuid().ToString();

    public bool Evaluate(EvaluationContext evaluationContext, ref object state)
    {
        var sf = new SecurityFault();
        sf.Operation = "Authorization";
        sf.ProblemType = "Authorization failed";
        throw new FaultException<SecurityFault>(sf);
    }
}

然后,客户端应用程序可以按如下方式捕获异常:

public class Program
{
    static void Main(string[] args)
    {
        var wcfClient = new MyService.ServiceClient();

        try
        {
            var result = wcfClient.Divide(10, 5);
            Console.WriteLine(result);
        }
        catch (FaultException<SecurityFault> securityFault)
        {
            Console.WriteLine(securityFault.Detail.Operation);
            Console.WriteLine(securityFault.Detail.ProblemType);
        }

        Console.ReadLine();
    }
}