Запретить ответ перенаправления XmlHttpRequest на сайте .Net MVC WS-Federation - PullRequest
5 голосов
/ 29 февраля 2012

Я использую аутентификацию WS Federated (Claims Aware) на сайте MVC 3, и у меня возникают проблемы с удержанием некоторых моих контроллеров API, которые отправляют JSON, для возврата перенаправления при сбое аутентификации.У меня есть область под названием API с несколькими контроллерами, которые просто возвращают JSON, все эти контроллеры наследуются от одного базового класса.Я хочу отправить законные 401 сообщения об ошибках вместо 302 перенаправлений, которые происходят по умолчанию.

Я следовал некоторым указаниям, которые нашел для создания пользовательского WSFederationAuthenticationModule в сочетании с фильтром, который я наложил на свои действия контроллера API:

public class WSFederationServiceAuthenticationModule : WSFederationAuthenticationModule
{
    private static Log4NetLoggingService logger = new Log4NetLoggingService();

    public const string IsServiceIndicator = "ROIP.IsService";

    protected override void OnAuthorizationFailed(AuthorizationFailedEventArgs e)
    {
        base.OnAuthorizationFailed(e);            

        var isService = HttpContext.Current.Items[IsServiceIndicator];

        if (isService != null)
        {
            logger.Info("WSFedService: Found IsService");
            e.RedirectToIdentityProvider = false;
        }
        else
        {
            logger.Info("WSFedService: Did not find IsService");
        }
    }
}

public class WSFederationServiceAuthAttribute : ActionFilterAttribute
{
    private static Log4NetLoggingService logger = new Log4NetLoggingService();

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        base.OnActionExecuting(filterContext);

        // Set an item that indicates this is a service request, do not redirect.
        logger.Info("WSFedService: Setting IsService");
        HttpContext.Current.Items[WSFederationServiceAuthenticationModule.IsServiceIndicator] = 1;
    }
}

Но моя регистрация показывает, что я никогда не нахожу элемент IsService в Предметах:

{INFO}02/29 03:39:21 - WSFedService: Setting IsService
{INFO}02/29 03:39:32 - WSFedService: Setting IsService
{INFO}02/29 03:39:32 - WSFedService: Setting IsService
{INFO}02/29 03:50:39 - WSFedService: Did not find IsService
{INFO}02/29 03:53:16 - WSFedService: Did not find IsService
{INFO}02/29 03:53:29 - WSFedService: Did not find IsService

Я думаю, что это может быть проблема из-за того, что HttpContext.Current не являетсяТо же самое между фильтром и модулем, но я не уверен.

Другой вариант, который я пробовал, состоял в том, чтобы подписаться на событие FederatedAuthentication.WSFederationAuthenticationModule.RedirectingToIdentityProvider в событии Application_Start моего Global.asax.cs, ноWSFederationAuthenticationModule в это время не имеет значения.

private void ConfigureWSFederationAuthentication()
{
    bool hasFederatedAuthentication = false;
    try
    {
        if (FederatedAuthentication.WSFederationAuthenticationModule != null)
        {
            hasFederatedAuthentication = true;
        }
    }
    catch
    {
        hasFederatedAuthentication = false;
    }

    if (hasFederatedAuthentication)
    {
        Logger.Info("WSFederation: Registering for Event Handler");
        FederatedAuthentication.WSFederationAuthenticationModule.RedirectingToIdentityProvider += (s, e) =>
            {
                var msg = string.Empty;
                try
                {
                    if (HttpContext.Current.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
                    {
                        e.Cancel = true;
                        msg = "Found XMLHttpRequest header";
                    }
                    else
                    {
                        msg = "Did not find XMLHttpRequest header";
                    }
                }
                catch (Exception ex)
                {
                    msg = "WSFederation: Event Handler Error: " + ex.Message;
                }

                Logger.Info("WSFederation: Redirecting from Event Handler: " + msg);
            };
    }
    else
    {
        Logger.Info("WSFederation: Null WSFederationAuthenticationModule");
    }
}

Я хотел бы знать, как заставить работать первый параметр, или где мне следует подписаться на событие RedirectingToIdentityProvider.

Ответы [ 3 ]

9 голосов
/ 07 марта 2012

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

Моя проблема заключалась в том, что HttpContext.Current.Items не был 'не совпадает между моим ActionFilterAttribute и WSFederationAuthenticationModule, поэтому я закончил проверку контекста и добавил несколько проверок, похожих на Пример подавления перенаправления форм Phil Haacks

Вот что мой обновленный пользовательскийWSFederationAuthenticationModule выглядит так:

public class WSFederationServiceAuthenticationModule : WSFederationAuthenticationModule
{
    private static Log4NetLoggingService logger = new Log4NetLoggingService();

    protected override void OnAuthorizationFailed(AuthorizationFailedEventArgs e)
    {
        base.OnAuthorizationFailed(e);            

        var context = HttpContext.Current;
        var req = context.Request;
        var resp = context.Response;

        if (req == null || resp == null)
        {
            logger.Info("WSFedService: Did not find Request or Response");
            return;
        }

        if ((resp.StatusCode == 302 || resp.StatusCode == 401) && req.Headers["X-Requested-With"] == "XMLHttpRequest")
        {
            logger.Info("WSFedService: Found Redirect and Header");
            e.RedirectToIdentityProvider = false;
        }
        else
        {
            logger.Info(string.Format("WSFedService: Did not find redirect status code or XMLHttpRequest Header: {0}", resp.StatusCode));
        }

    }
}

И, конечно, вам нужно добавить это в ваш web.config вместо модуля аутентификации по умолчанию:

<system.web>
    <httpModules>
        <!-- Old and Busted...
        <add name="WSFederationAuthenticationModule"
           type="Microsoft.IdentityModel.Web.WSFederationAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
        -->

        <!-- New Hotness... -->
        <add name="WSFederationAuthenticationModule"
           type="MyApp.Web.Authentication.WSFederationServiceAuthenticationModule, MyApp.Web" />
    </httpModules>
</system.web>

<system.webServer>
    <modules>
        <!-- Old and Busted...
        <add name="WSFederationAuthenticationModule"
           type="Microsoft.IdentityModel.Web.WSFederationAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
           preCondition="managedHandler"/>
        -->

        <!-- New Hotness... -->
        <add name="WSFederationAuthenticationModule"
           type="MyApp.Web.Authentication.WSFederationServiceAuthenticationModule, MyApp.Web"
           preCondition="managedHandler"/>

    </modules>
</system.webServer>
3 голосов
/ 30 октября 2012

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

.. И, в зависимости от вашей ситуации, может быть проще / менее сложно обработать событие неудачной авторизации в Global.asax и выполнить там проверку.

Эта ссылкато, что я следовал: http://msdn.microsoft.com/en-us/library/system.identitymodel.services.wsfederationauthenticationmodule.authorizationfailed.aspx

.. И это кажется простым.

1 голос
/ 20 апреля 2018

В моем случае я разместил мои api-файлы по пути "/ api" на веб-сайте, которые защищены с помощью аутентификации JWT.

Для исправления этой проблемы в WSFederationAuthenticationModule были сделаны следующие переопределения (конечно, зарегистрируйте этот пользовательский модуль в web.config, System.WebServer ).

public class CustomWSFederationAuthenticationModule : System.IdentityModel.Services.WSFederationAuthenticationModule
{
    protected override void OnAuthorizationFailed(AuthorizationFailedEventArgs e)
    {
        if (!IsApiCall())
            e.RedirectToIdentityProvider = false;
        base.OnAuthorizationFailed(e);
    }

    protected override void OnEndRequest(object sender, EventArgs args)
    {
        if (!IsApiCall())
            base.OnEndRequest(sender, args);
    }

    private bool IsApiCall()
    {
        return (HttpContext.Current.Request.Path.ToLowerInvariant().Contains("/api/"));
    }
}
...