Междоменные соединения SignalR с самообслуживанием и аутентификацией
У меня проблема с CORS при самообслуживании SignalR с OWIN, что происходит только при попытке включить аутентификацию.
Ошибка, которую я получаю в своем веб-браузере:
XMLHttpRequest не может загрузить http://.../signalr/negotiate?[snip] Происхождение... не разрешено Access-Control-Allow-Origin
Это происходит только в том случае, если я включаю проверку подлинности на своем самообслуживаемом сервере с помощью подхода в этом ответе:
public void Configuration(IAppBuilder app)
{
var listener = (HttpListener)app.Properties[typeof(HttpListener).FullName];
listener.AuthenticationSchemes = AuthenticationSchemes.Ntlm;
app.MapHubs(new HubConfiguration { EnableCrossDomain = true });
}
Если я прокомментирую строку AuthenticationSchemes
, то работает CORS (и я проверил все в эти инструкции). Я получаю ту же проблему, если я использую другие схемы аутентификации, чем NTLM.
Используя Fiddler, чтобы проверить, что происходит, без проверки подлинности я вижу, что необходимые заголовки CORS возвращаются с сервера:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: [мой сервер]
Однако после включения проверки подлинности я получаю ответ 401, в котором отсутствуют эти заголовки. Все запросы имеют необходимый заголовок Origin
.
Изучив исходный код SignalR похоже, что заголовки устанавливаются, но, предположительно, с помощью аутентификации HttpListener
отправляет начальный ответ 401 без удара этого кода.
Итак, я думаю, что мой вопрос: как мне включить HttpListener
заголовок Access-Control-Allow-Origin
в его согласовании протоколов аутентификации?
Ответы
Ответ 1
Я получил аутентификацию NTLM для работы с междоменным сигналом R, самостоятельно размещенным в OWIN, разрешив анонимный доступ к предполетным запросам.
Что нужно сделать, так это создать делегата для выбора схемы проверки подлинности, которая ищет заголовки запросов перед полетом, и позволяет это через анонимность. Все остальные запросы будут использовать NTLM.
public void Configuration(IAppBuilder appBuilder)
{
var listener = (HttpListener)appBuilder.Properties[typeof(HttpListener).FullName];
listener.AuthenticationSchemeSelectorDelegate += AuthenticationSchemeSelectorDelegate;
}
private AuthenticationSchemes AuthenticationSchemeSelectorDelegate(HttpListenerRequest httpRequest)
{
if (httpRequest.Headers.Get("Access-Control-Request-Method")!=null)
return AuthenticationSchemes.Anonymous;
else
return AuthenticationSchemes.Ntlm;
}
Ответ 2
Я предполагаю, что вы используете Chrome, который очень бесполезно говорит вам, что эти заголовки отсутствуют, и что это проблема, когда вы, вероятно, просто забыли установить XMLHttpRequest
withCredentials
до true
.
Если вы используете jQuery, вы можете сделать это для всех запросов с помощью:
$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
options.xhrFields = { withCredentials: true };
});
Вам также нужно сделать правильные действия с запросами OPTIONS
, как в другом ответе.