Поддержка CORS в службах REST WCF

У меня есть служба WCF REST, размещенная в службе Windows, и я бы хотел отправить HTTP-заголовок Access-Control-Allow-Origin (определенный как часть CORS) с каждым ответом.

Мое решение заключалось в следующем: IDispatchMessageInspector:

public void BeforeSendReply(ref Message reply, object correlationState)
{
    var httpResponse = reply.Properties["httpResponse"] as HttpResponseMessageProperty;
    if (httpResponse != null)
    {
        // test of CORS
        httpResponse.Headers["Access-Control-Allow-Origin"] = "*";
    }
}

Обычно это сработает, но, к сожалению, моя служба также использует базовую авторизацию HTTP, а это означает, что когда запрос приходит без заголовка авторизации, WCF автоматически отправляет ответ 401 с запросом учетных данных. К сожалению, WCF не вызывает мой IDispatchMessageInspector во время этого первоначального обмена, поэтому заголовок Access-Control-Allow-Origin не добавляется к первоначальному обмену.

Проблема возникает, когда я пытаюсь вызвать службу из браузера. CORS указывает, что запросы перекрестного происхождения должны разрешаться только в том случае, если домен источника совпадает с доменом, указанным в заголовке ответа Access-Control-Allow-Origin (* соответствует всем доменам). К сожалению, когда браузер видит исходный ответ 401 без заголовка Access-Control-Allow-Origin, он предотвращает доступ (в соответствии с той же политикой происхождения).

Можно ли добавить заголовок в исходный ответ 401, отправленный автоматически WCF?

Ответ 1

Этот парень спас мой день.

http://blogs.microsoft.co.il/blogs/idof/archive/2011/07.aspx

Я собираюсь разместить некоторые из его заметок здесь, на случай, если однажды веб-страница умрет. (Я ненавижу находить ссылки "Ваш ответ верен ЗДЕСЬ", а затем ссылка мертва.)

<behaviors> 
  <endpointBehaviors> 
    <behavior name="webSupport"> 
      <webHttp /> 
      <CorsSupport /> 
    </behavior> 
  </endpointBehaviors> 
</behaviors> 
<extensions> 
  <behaviorExtensions> 
    <add name="CorsSupport" type="WebHttpCors.CorsSupportBehaviorElement, WebHttpCors, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 
  </behaviorExtensions> 
</extensions> 
<services> 
  <service name="Service.JSonService"> 
    <endpoint address="http://localhost:8080" behaviorConfiguration="webSupport' binding="webHttpBinding" contract="Service.IJSonService" /> 
  </service> 
</services>

Теперь вам нужно найти его загружаемую библиотеку под названием "WebHttpCors.dll".

Но там (выше) достаточно, чтобы помочь вам Google/Bing ваш путь к решению.

Часть, которая подталкивала меня к циклу (в моем сценарии), заключается в том, что IE работал, но Firefox не работал.

Моя исходная страница была:

http://localhost:53692/test/WCFCallTestViaJQ14.htm

Так что мой сервис по адресу:

http://localhost:8002/MyWCFService/MyWCFMethodByWebGet?state=NC&city=Raleigh

Итак, у меня был локальный трафик & lt; & lt; - >> localhost.

**** Но порты были разные. (53692 и 8002) ****

IE был в порядке с этим. Firefox был не в порядке с этим.

Затем вы должны помнить, что каждый браузер обрабатывает свои запросы .Send() по-своему (то есть внутри JQUERY).

Все это имеет смысл сейчас.

//JavaScript snipplet from JQuery library

if (window.XMLHttpRequest) {

    returnObject = new XMLHttpRequest();

} else if (window.ActiveXObject) {

    returnObject = new ActiveXObject("Microsoft.XMLHTTP");

} else {

msg = "Your browser does not support AJAX!";

}

Вот некоторые ключевые слова, фразы, которые я гуглил/разглагольствовал, что, наконец, привело меня куда-то.

    Result: [Exception... "Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIXMLHttpRequest.statusText]" nsresult: "0x80040111 (NS_ERROR_NOT_AVAILABLE)" location: "JS frame :: http://localhost:53692/test/WCFCallTestViaJQ14.htm :: HandleJQueryError :: line 326" data: no]


XMLHttpRequest Send "NS_ERROR_FAILURE"

JQuery Ajax WCF Self Hosted CORS JSON

ТЕПЕРЬ, ВАМ НУЖНО ПРОЧИТАТЬ ЕГО БЛОГОВЫЕ БЛОГИ, ЧТОБЫ ПОНИМАТЬ, ЧТО ДЕЛАЕТ КОД:

Например, он говорит:

Заголовок 'Access-Control-Allow-Origin' со значением '*'

Это может или не может быть то, что вы хотите. Возможно, вы захотите лучше контролировать это значение (заголовки) и другие (методы и источники).

Среда разработки это одно. (Используйте все *, что вы хотите).

Производство - это что-то другое, вы можете настроить эти * значения на что-то более различающее. Короче говоря, вам нужно понять, что на самом деле делает для вас CORS с точки зрения безопасности, а не просто добавить поведение, которое позволяет все.

  allowed-origins: '*'
  allowed-headers: '*'
  allowed-methods: '*'

Ответ 2

Для достижения того, что вы хотите, вам нужно самому справиться с авторизацией, что возможно путем impelementing + регистрации HttpModule... там вы будете выпускать 401 и вместе с ним любой HTTP-заголовок, который вы хотите... есть даже образец реализация здесь на SO - см. Добавление базового HTTP-аутентификации в службу WCF REST

EDIT - после комментария от OP:

Так как в комментарии OP говорится, что он сам по себе, решение не с HTTPModule, а на самом деле с IDispatchMessageInspector.BeforeSendReply и с IDispatchMessageInspector.AfterReceiveRequest.

Авторизация должна быть настроена на "Нет" и пользовательский реализован/обработан в IDispatchMessageInspector - таким образом вы можете добавить любой заголовок при выпуске 401. В противном случае обработка начального времени Basic Auth не вызовет ваш IDispatchMessageInspector до правильного/положительного Auth.

Несмотря на то, что это работает BEWARE, это означает, что вы сами внедряете код security-sensitiv и, следовательно, должны принимать меры для обеспечения правильной реализации...

Ответ 3

Добавление следующей строки в первый метод, вызываемый в службе WCF, сработало для меня.

WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");

Требуется следующий импорт

System.ServiceModel.Web;

Ссылайтесь на оригинальный ответ