为什么ServiceConfiguration.GetCurrent可以在注销/登录后返回空对象引用?

时间:2012-08-21 12:50:41

标签: asp.net azure wif acs

我有一个Windows Azure应用程序,包括一个MVC4 Web角色和一组服务角色,包括工作者和Web,都是使用2012年6月的SDK构建的。我的MVC角色使用WIF / ACS和被动重定向进行保护。我的服务只能通过内部端点访问,并且不受保护。

使用WIF / ACS进行身份验证和授权通常可以正常工作,但有时如果我退出一个帐户然后快速从我的浏览器历史记录返回到索引页面,则会被要求再次登录,我是而是提供以下YSOD:

 Object reference not set to an instance of an object.
 Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

 Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.

 Source Error:

 An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

 Stack Trace:

 [NullReferenceException: Object reference not set to an instance of an object.]
    Microsoft.IdentityModel.Configuration.ServiceConfiguration.GetCurrent() +123
    Microsoft.IdentityModel.Claims.ClaimsPrincipal.CreateFromHttpContext(HttpContext httpContext, Boolean clientCertificateAuthenticationEnabled) +29
    Microsoft.IdentityModel.Web.WSFederationAuthenticationModule.OnPostAuthenticateRequest(Object sender, EventArgs e) +91
    System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +79
    System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +269

我一开始认为这可能是一个cookie未被清除的情况,但令人惊讶的是整个MVC网站似乎已经崩溃,并且从任何浏览器和其他机器都可以看到此错误。我发现的唯一解决方法是重新启动角色。

由于被动重定向是在web.config中设置的,并且是使用STS向导自动应用的,因此我怀疑当我将用户注销时我做错了。我的注销代码如下所示:

public ActionResult CompleteLogOut(Boolean total, String provider = "")
    {
        WSFederationAuthenticationModule fam = FederatedAuthentication.WSFederationAuthenticationModule;
        FormsAuthentication.SignOut();
        fam.SignOut(true);
        if (total)
        {
            provider = @"logout:" + provider;
            return Redirect(ConfigurationManager.AppSettings[provider]);
        }
        else
        {
            return RedirectToAction("Index");
        }
    }

...如果'total'为真,则用户将被重定向到其身份提供商的注销页面,在我的测试设置中为https://accounts.google.com/Logouthttps://login.live.com/login.srf?wa=wsignout1.0

我只注意到当我的退出是“总计”时发生的错误,但由于它在任何情况下都是间歇性错误,我无法确定这是否总是如此。

谷歌搜索错误引发了this,这似乎并不直接相关,但让我想知道在我退出后是否需要处理WSFederationAuthenticationModule?

有没有人遇到类似问题,或者有人知道问题可能是什么?

更新

“似乎整个MVC网站都崩溃了,而且这个错误在任何浏览器中都可以看到” - 事实上,我认为这是不对的。只有两个独立的用户遇到相同的错误,恰巧在同一时间。

1 个答案:

答案 0 :(得分:0)

嗯,好吧,我找到了答案,但我并不完全理解。

为了跟踪用户,我会在有人开始新会话时立即在Global.asax中设置会话变量:

    protected void Session_Start()
    {
        HttpContext.Current.Session.Add("MySession", Session.SessionID);
    }

这使得MVC创建会话,因此我可以使用SessionID跟踪用户活动(否则MVC将为每个请求创建一个新会话)。

如果我在注销时明确处理了我的会话,那么上述错误就会消失:

    public ActionResult CompleteLogOut(Boolean total, String provider = "")
    {
        var fam = FederatedAuthentication.WSFederationAuthenticationModule;
        Session.Clear();
        Session.Abandon();
        FormsAuthentication.SignOut();
        try
        {
            fam.SignOut(true);
        }
        catch {}
        finally
        {
            try
            {
                fam.Dispose();
                fam = null;
            }
            catch { }
        }
        if (total)
        {
            provider = @"logout:" + provider;
            return Redirect(ConfigurationManager.AppSettings[provider]);
        }
        else
        {
            return Redirect(ConfigurationManager.AppSettings["LoggedOutRedirect"]);
        }
    }
}

如果用户没有完全记录他们的身份提供者,我还需要重定向到我的主页的绝对URI,而不仅仅是重定向到操作方法。

不确定为什么必须清除并放弃会话以使WIF再次运行。 WIF是否在内部使用会话?也许有人可以放弃更多的光,但无论如何,上面的注销程序都可以起作用,并且希望将来可能会让其他人免于摔跤同样的错误。