Хотите, чтобы исключение PrincipalPermission SecurityException для службы REST возвращало 403, а не 400 ошибочных запроса - PullRequest
0 голосов
/ 29 июня 2018

У меня есть служба 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[]&amp; outputs)
            at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc&amp; rpc)
            at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc&amp; rpc)
            at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc&amp; rpc)
            at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)</p>
    </div>
  </body>
</html>

1 Ответ

0 голосов
/ 29 июня 2018

Вы можете реализовать 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 или в конфигурации.

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
    }
}
...