我已经用Google搜索并查看了this和this帖子,但我仍然遇到问题,我的电话没有正常中止。方案如下:
有一个客户端(服务器)可以访问Web服务提供的一个特定服务操作。 webservice提供通常可访问的其他方法,只是特定的方法仅限于一个特定的IP地址。界面如下所示:
[ServiceContract( Namespace = "http://some.where/abc/2014/01" )]
public interface IWsConnector : IDisposable
{
[OperationContract( ProtectionLevel = ProtectionLevel.EncryptAndSign )]
[FaultContract( typeof( ServiceFault ) )]
Collection<HostedExchangeObject> GetSomeObjects(
string anIdentifier, int aNumber );
// This is the service operation that shall be protected
[OperationContract( ProtectionLevel = ProtectionLevel.EncryptAndSign )]
[FaultContract( typeof( ServiceFault ) )]
[IpFilter]
Collection<HostedExchangeObject> GetSomeObjectsForInternalUse(
string anIdentifier );
[OperationContract( ProtectionLevel = ProtectionLevel.EncryptAndSign )]
[FaultContract( typeof( ServiceFault ) )]
Collection<HostedExchangeObject> GetSomeObjectsByFlag(
string anIdentifier,
int aNumber,
SomeObjectType someExchangeObjectType );
}
用于界面中服务操作的IpFilter属性如下所示(代码的相关部分):
[AttributeUsage( AttributeTargets.Method )]
public sealed class IpFilterAttribute : Attribute, IOperationBehavior, IParameterInspector
{
...
public object BeforeCall( string operationName, object[] inputs )
{
RemoteEndpointMessageProperty clientEndpoint =
OperationContext.Current.IncomingMessageProperties[
RemoteEndpointMessageProperty.Name ] as RemoteEndpointMessageProperty;
if ( clientEndpoint != null )
{
IpAddressRange ipAddressRange =
new IpAddressRange(
IPAddress.Parse( RangeFrom ), IPAddress.Parse( RangeTo ) );
if ( !ipAddressRange.IsInRange( IPAddress.Parse( clientEndpoint.Address ) ) )
{
ConditionalLogger conditionalLogger =
new ConditionalLogger( "SomeInformation" );
conditionalLogger.LogAndThrowFaultException(
Severity.Error,
ServiceOperationNotPermittedForRequestingClient,
operationName,
clientEndpoint.Address
);
}
}
return null;
}
...
}
使用配置(设置)中的值在默认构造函数中设置 RangeFrom
和RangeTo
。原因是我们不能使用构造函数的参数,因为我们需要部署到不同的环境,每个环境都需要不同的IP地址范围。
当我尝试在允许的IP地址范围内从客户端访问服务操作时,一切正常。
当我尝试从允许的IP地址范围之外的客户端访问服务操作时,一切正常从客户端(即不允许访问操作,没有数据被分开传输来自FaultException)。
问题是,在服务器端,(可能长时间运行)操作仍在执行而不是中止。不是BeforeCall
检查和中止通话的正确方法吗?按照上面提到的链接帖子,抛出异常也应该是中止通话的正确方法,所以我不知道还有什么可能是错的?如何避免在服务器端执行与此服务操作相关的代码?
答案 0 :(得分:0)
客户端调用IpFilterAttribute
方法时是否会执行GetSomeObjectsForInternalUse
?在BeforeCall
方法中抛出异常而不是在ConditionalLogger
内抛出异常,看看它是否有效。这里有关于Allow/Deny Access by IP Address in WCF的好文章。
编辑:试试此代码
public class IpFilterAttribute : Attribute, IOperationBehavior, IParameterInspector
{
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
dispatchOperation.ParameterInspectors.Add(this);
}
public void AddBindingParameters(OperationDescription operationDescription,
BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
}
public void Validate(OperationDescription operationDescription)
{
}
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
{
}
public object BeforeCall(string operationName, object[] inputs)
{
var clientEndpoint =
OperationContext.Current.IncomingMessageProperties[RemoteEndpointMessageProperty.Name] as
RemoteEndpointMessageProperty;
throw new SecurityException(string.Format("Calling method '{0}' is not allowed from address '{1}'.",
operationName, clientEndpoint.Address));
return null;
}
}