6

我在 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 事件中订阅该FederatedAuthentication.WSFederationAuthenticationModule.RedirectingToIdentityProvider事件Application_Start,但当时 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事件。

4

3 回答 3

9

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

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

这是我更新后的自定义的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>
于 2012-03-07T19:22:26.410 回答
3

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

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

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

..而且看起来很简单。

于 2012-10-29T21:50:32.790 回答
1

在我的情况下,我在网站的路径“/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/"));
    }
}
于 2018-04-20T12:50:24.813 回答