我已经为WCF服务实现了自定义IAuthorizationPolicy
。它工作正常,除了授权失败时,客户端会收到毫无意义的错误。
如果我只是从 Evaluate
方法中的 return false
,客户端只会接收到以下内容:
System.ServiceModel.faultException :'由于内部错误,服务器无法处理请求。有关该错误的更多信息,请打开服务器上的InccialexceptionDetailInFaults(来自ServiceBehaviorAttribute或来自配置行为的服务(,以便将异常信息发送回客户端,或者按照Microsoft .NET .NET .NET .NET Framework Wormerwork和SDK Document和Microsoft sdk framework和按照检查服务器跟踪日志。'
如果我扔了 FaultException<MyCustomErrorDetails>
,客户会收到以下内容:
System.ServiceModel.CommunicationException:接收到http响应http://localhost:9034/service1.svc时发生了错误。这可能是由于服务端点绑定不使用HTTP协议。这也可能是由于服务器中止HTTP请求上下文(可能是由于服务关闭(。有关更多详细信息,请参见服务器日志。
它的帮助甚至不那么有用。
如何将有意义的错误返回给客户端,例如"授权失败"?
可以通过行为配置来完成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();
}
}