SignalR, похоже, использует аутентификацию Windows вместо анонимной аутентификации - PullRequest
2 голосов
/ 09 мая 2019

У меня есть веб-приложение, использующее IIS 10 с включенной аутентификацией Windows и анонимной аутентификацией. Приложение использует SignalR 2.4.0 и зависимость от SQL для циклического просмотра изображений каждые десять секунд, пользователь может использовать устройство, чтобы остановить цикл и отобразить презентацию в своем собственном темпе, прежде чем вернуться в цикл. Проблема, с которой я сталкиваюсь, заключается в том, что большинство приложений должны использовать проверку подлинности Windows, а некоторые контроллеры должны разрешать анонимный доступ. Однако анонимный пользователь (например, Smart TV или компьютер, не подключенный к домену) не может отображать изображения без предварительной аутентификации.

Я мог бы неправильно понять ситуацию, но я полагаю, что это потому, что signalR использует аутентификацию Windows. Если я закрою диалоговое окно с запросом имени пользователя и пароля, консоль для Microsoft Edge отобразит следующее сообщение

HTTP401: DENIED - Запрошенный ресурс требует аутентификации пользователя. (XHR) GET - http://MyWebsite/Home/signalr/negotiate?clientProtocol=2.0&connectionData=%5B%7B%22name%22%3A%22signalrhub%22%7D%5D&_=1557410422010

Большинство изменений кода, которые я пробовал, были в файле web.config. Основной файл web.config имеет режим аутентификации

<authentication mode="Windows" />

Однако у меня также есть выпуск web.config, который содержит настройку, разрешающую анонимность для контроллера дисплея и сигнализатора

<location path="Area/Controller" xdt:Transform="InsertIfMissing" xdt:Locator="Match(path)">
    <system.web>
      <authorization>
        <allow users="?" />
      </authorization>
    </system.web>
  </location>
  <location path="signalr" xdt:Transform="InsertIfMissing" xdt:Locator="Match(path)">
    <system.web>
      <authorization>
        <allow users="?" />
      </authorization>
    </system.web>
  </location>

Сначала я подумал, что мне нужно добавить подстановочный знак для пути местоположения, чтобы он выглядел примерно так:

<location path="signalr/*" xdt:Transform="InsertIfMissing" xdt:Locator="Match(path)">

или

<location path="signalr/negotiate*" xdt:Transform="InsertIfMissing" xdt:Locator="Match(path)">

но при поиске и тестировании он, кажется, не принимает его.

Я также пытался явно разрешить анонимную аутентификацию для путей, но я получил ошибку 500, прежде чем она достигла стадии аутентификации

<location path="Area/Controller" xdt:Transform="InsertIfMissing" xdt:Locator="Match(path)">
    <system.web>
      <authorization>
        <allow users="*" />
      </authorization>
    </system.web>
    <system.webServer>
      <security>
        <authentication>
          <anonymousAuthentication enabled="true" />
        </authentication>
      </security>
    </system.webServer>
  </location>
  <location path="signalr" xdt:Transform="InsertIfMissing" xdt:Locator="Match(path)">
    <system.web>
      <authorization>
        <allow users="*" />
      </authorization>
    </system.web>
    <system.webServer>
      <security>
        <authentication>
          <anonymousAuthentication enabled="true" />
        </authentication>
      </security>
    </system.webServer>
  </location>

Я также установил контроллер, чтобы разрешить анонимный

[AllowAnonymous]
 public class Controller
{
}

PartialView, выполняющий сценарий signalR, запрашивает аутентификацию при достижении connection.hub.start

<input type="hidden" name="connectionId" id="connectionId" />

<div id="divImageViewer"></div>

@Scripts.Render("~/bundles/jquery_signalR")

<script src="@Model.SignalRHubsUrl" type="text/javascript"></script>

@Html.HiddenFor(model => Model.MyModel.ModelItem)

<script type="text/javascript">
    $(function () {
        setTimeout(function () {
            $.connection.hub.start()
                .done(function () {
                    console.log("starting..."); //doesn't display in the console
                    var cid = $.connection.hub.id;
                    $("#connectionId").val(cid);
                    console.log("connected! Id: " + cid);
                    //do stuff
                })
                .fail(function (reason) {
                    console.log("SignalR connection failed: " + reason); //does display in the console after closing the dialog box
                });
    }, 5000); // Start connection after 5 seconds.
}

</script>

В конечном счете, я бы хотел сохранить аутентификацию Windows на месте для большинства веб-приложений, но при этом разрешить анонимный доступ для некоторых небольших частей.

Также извините, если большая часть этого - бесполезная тарабарщина, многое из этого все еще ново для меня, особенно javascript и jquery.

1 Ответ

0 голосов
/ 10 мая 2019

После получения некоторой помощи удалось сузить ее до строки, прокомментированной ниже. Как только это было удалено, SignalR прошел как анонимный без проблем.

[assembly: OwinStartupAttribute(typeof(Go.Startup))]
namespace MyName
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            var container = CompositionRoot.Compose();
            var controllerFactory = new InjectableControllerFactory(container);
            ControllerBuilder.Current.SetControllerFactory(controllerFactory);
            MvcSiteMapProviderConfig.Register(container);

            app.CreatePerOwinContext(ApplicationDbContext.Create);
            app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
            app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
            app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);

            //GlobalHost.HubPipeline.RequireAuthentication(); <---------

            app.MapSignalR(new HubConfiguration
            {
                EnableJSONP = true,
                EnableJavaScriptProxies = true,
                EnableDetailedErrors = true
            });

        }
    }
}
...