0

我有一个 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 站点都崩溃了,并且从任何浏览器都可以看到这个错误”——事实上,我认为这是不对的。只有两个不同的用户遇到相同的错误,巧合的是在同一时间。

4

1 回答 1

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,而不仅仅是重定向到 action 方法。

不知道为什么必须清除和放弃会话才能使 WIF 再次工作。WIF 是否在内部使用会话?也许有人可以提供更多的信息,但无论如何,上面的注销例程都有效,希望将来可以避免其他人与同样的错误搏斗。

于 2012-08-22T13:38:15.173 回答