希望 REST 服务上的 PrincipalPermission SecurityException 到 return 403,而不是 400 错误请求
Want a PrincipalPermission SecurityException on REST service to return 403, not 400 Bad Request
我有一个用 PrincipalPermission 要求装饰的 RESTful (WCF) 服务。如果用户不担任该角色,我希望得到 403 FORBIDDEN
响应,而是得到 400 BAD REQUEST
。经过反思,这是有道理的——当委托人不担任该角色时,需求会触发 SecurityException
;这与通过 web.config.
中的 <authorization>
标记授予访问权限不同
但是,400 BAD REQUEST
没有意义...请求没有格式错误,我只是无权拨打电话。 400
响应意味着我可以修复请求并重试,但永远不会成功。
我如何拦截或映射 SecurityException
到更合适的响应(最好是 403 FORBIDDEN
)?
修饰方法:
[PrincipalPermission(SecurityAction.Demand, Role = "FST")]
public string TestNoPermissions(string NetworkId) {
return "Call succeeded";
}
回复:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Request Error</title>
<style>BODY { color: #000000; ...;}</style>
</head>
<body>
<div id="content">
<p class="heading1">Request Error</p>
<p>The server encountered an error processing the request. The exception message is 'Access is denied.'. See server logs for more details. The exception stack trace is: </p>
<p> at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)</p>
</div>
</body>
</html>
您可以使用状态代码实施 IErrorHandler
to intercept the SecurityException
. and then provide a WebFaultException
。
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
if (error is SecurityException)
{
var faultEx = new WebFaultException<string>("Forbidden", HttpStatusCode.Forbidden)
fault = Message.CreateMessage(version, faultEx.CreateMessageFault(), null);
}
}
请注意,这是未经测试的——安全异常有一个在框架/管道中迷失的坏习惯,但这个想法对于评论来说有点长。
通常您会添加带有行为的自定义 IErrorHandler,该行为可以在您的 DI 代码或配置中进行配置。
public class ErrorHandlerBehavior : IServiceBehavior
{
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
// not implemented
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (var dispatcherBase in serviceHostBase.ChannelDispatchers)
{
var dispatcher = dispatcherBase as ChannelDispatcher;
if (dispatcher != null)
dispatcher.ErrorHandlers.Add(new MyCustomErrorHandler());
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
// not implemented
}
}
我有一个用 PrincipalPermission 要求装饰的 RESTful (WCF) 服务。如果用户不担任该角色,我希望得到 403 FORBIDDEN
响应,而是得到 400 BAD REQUEST
。经过反思,这是有道理的——当委托人不担任该角色时,需求会触发 SecurityException
;这与通过 web.config.
<authorization>
标记授予访问权限不同
但是,400 BAD REQUEST
没有意义...请求没有格式错误,我只是无权拨打电话。 400
响应意味着我可以修复请求并重试,但永远不会成功。
我如何拦截或映射 SecurityException
到更合适的响应(最好是 403 FORBIDDEN
)?
修饰方法:
[PrincipalPermission(SecurityAction.Demand, Role = "FST")]
public string TestNoPermissions(string NetworkId) {
return "Call succeeded";
}
回复:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Request Error</title>
<style>BODY { color: #000000; ...;}</style>
</head>
<body>
<div id="content">
<p class="heading1">Request Error</p>
<p>The server encountered an error processing the request. The exception message is 'Access is denied.'. See server logs for more details. The exception stack trace is: </p>
<p> at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)</p>
</div>
</body>
</html>
您可以使用状态代码实施 IErrorHandler
to intercept the SecurityException
. and then provide a WebFaultException
。
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
if (error is SecurityException)
{
var faultEx = new WebFaultException<string>("Forbidden", HttpStatusCode.Forbidden)
fault = Message.CreateMessage(version, faultEx.CreateMessageFault(), null);
}
}
请注意,这是未经测试的——安全异常有一个在框架/管道中迷失的坏习惯,但这个想法对于评论来说有点长。
通常您会添加带有行为的自定义 IErrorHandler,该行为可以在您的 DI 代码或配置中进行配置。
public class ErrorHandlerBehavior : IServiceBehavior
{
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
// not implemented
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (var dispatcherBase in serviceHostBase.ChannelDispatchers)
{
var dispatcher = dispatcherBase as ChannelDispatcher;
if (dispatcher != null)
dispatcher.ErrorHandlers.Add(new MyCustomErrorHandler());
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
// not implemented
}
}