Хотите, чтобы исключение PrincipalPermission SecurityException для службы REST возвращало 403, а не 400 ошибочных запроса
У меня есть служба RESTful (WCF), оформленная в соответствии с требованиями PrincipalPermission. Я ожидал 403 FORBIDDEN
ответ, если пользователь не удерживает роль, но получает 400 BAD REQUEST
вместо. Если подумать, это имеет смысл - спрос вызывает SecurityException
когда директор не держит роль; это не то же самое, что предоставление доступа через <authorization>
тег в web.config.
Тем не менее, 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>
1 ответ
Вы могли бы реализовать IErrorHandler
перехватить SecurityException
, а затем предоставить 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 или в config.
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
}
}