【问题标题】:Prevent XmlHttpRequest redirect response in .Net MVC WS-Federation Site防止 .Net MVC WS-Federation 站点中的 XmlHttpRequest 重定向响应
【发布时间】:2018-04-20 20:50:24
【问题描述】:

我在 MVC 3 站点上使用 WS 联合(声明感知)身份验证,并且在身份验证失败时无法阻止发送 JSON 的一些 API 控制器返回重定向。我有一个名为 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;
    }
}

但我的日志显示我从未在 Items 中找到 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 不一样的问题,但我不确定。

我尝试的另一个选项是订阅我的 Global.asax.cs 的 Application_Start 事件中的 FederatedAuthentication.WSFederationAuthenticationModule.RedirectingToIdentityProvider 事件,但当时 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 事件。

【问题讨论】:

    标签: asp.net-mvc ws-federation


    【解决方案1】:

    我想我已经找到了这个问题的答案,并想回过头来为世界上可能遇到这个问题的任何人留下一个答案。

    我的问题是HttpContext.Current.Items 在我的ActionFilterAttributeWSFederationAuthenticationModule 之间不匹配,所以我最终检查了上下文并添加了一些类似于Phil Haacks Forms Redirect Suppress Example 的检查

    这是我更新后的自定义 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>
    

    【讨论】:

      【解决方案2】:

      我意识到这个线程很古老,但是我在尝试解决相同的问题时遇到了它(我有想要与活动客户端一起使用的 web api,如果身份验证失败,我想发送 401 而不是重定向。)

      ..而且,根据您的情况,处理 Global.asax 中的授权失败事件并在那里进行检查可能更容易/更少。

      这个链接是我一直关注的:http://msdn.microsoft.com/en-us/library/system.identitymodel.services.wsfederationauthenticationmodule.authorizationfailed.aspx

      ..而且看起来很简单。

      【讨论】:

      • 我已经为同一个事件做了完全一样的使用和事​​件处理程序。像魅力一样工作!
      【解决方案3】:

      在我的情况下,我在网站的路径“/api”下托管了我的 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/"));
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2010-09-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多