如何在请求早期使错误的身份验证 cookie 失效?

EAM*_*ann 2 cookies asp.net-mvc forms-authentication .aspxauth

设想

我开发了一个将托管在 Windows Azure 中的 MVC 应用程序。在开发过程中,我针对本地数据库和本地用户成员资格服务进行测试。在生产中,应用程序连接 SQL Azure 数据库和云托管的用户会员服务。

有时,我会使用仅存在于我的本地计算机上的用户帐户登录到该网站的本地版本。如果我忘记注销但将机器退出测试模式,事情就会开始出现问题。

问题

我将hosts文件设置为指向应用程序 URL,127.255.0.0以便 Azure 模拟器在本地处理浏览器请求。这也意味着我的测试应用程序和生产应用程序使用相同的主机名 - 一个的 cookie 被视为另一个的有效 cookie。

如果我登录到本地系统,ASPXAUTH则会为该域创建一个 cookie,其中包含本地系统中用户的凭据。如果我忘记注销并将hosts文件切换回正常状态(浏览器请求转到实时应用程序),它会ASPXAUTH向服务器发送相同的 cookie。

由于该用户不存在于服务器上,仅存在于本地,因此任何请求都会Membership.GetUser().Email返回对象空异常。

我想做的事

理想情况下,我可以在请求的早期注入一些代码来检查用户是否存在。就像是:

MembershipUser user = Membership.GetUser();
if(user == null) {
    FormsAuthentication.SignOut();
}
Run Code Online (Sandbox Code Playgroud)

这将自动删除ASPXAUTH无效用户的 cookie。但我该把它放在哪里呢?我开始查看我的控制器 - 所有控制器都继承自一个BaseController类,但即使将此代码放入基本控制器的构造函数中也还不够早。我也查看了Global.asax,但我不确定哪个事件最适合将此操作绑定到。

另外,我什至不确定这是正确的做事方式。如果不是,那么在像我现在这样依赖会员级别之前,确保身份验证 cookie 适用于有效用户的最佳方法是什么?

Kib*_*ria 5

您可以在 global.aspx 中处理以下事件:

public void FormsAuthentication_OnAuthenticate(object sender, FormsAuthenticationEventArgs args)
{ 
}
Run Code Online (Sandbox Code Playgroud)

编辑:

在上面的方法中,Membership.GetUser()将返回null,因为它从属性中获取 userName HttpContext.Current.User.Identity.Name,并且在这种情况下用户尚未经过身份验证。当FormsAuthenticationModule引发Authenticate事件时,将调用上述方法。你可以像这样处理这个事件:

public void FormsAuthentication_OnAuthenticate(object sender, FormsAuthenticationEventArgs args)
{
    if (FormsAuthentication.CookiesSupported &&
            Request.Cookies[FormsAuthentication.FormsCookieName] != null)
    {
        try
        {
            var formsAuthTicket = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value);

            MembershipUser user = Membership.GetUser(formsAuthTicket.Name);
            if (user == null)
            {
                FormsAuthentication.SignOut();
                Request.Cookies[FormsAuthentication.FormsCookieName].Value = null;
            }
        }
        catch (Exception ex)
        {
            //TODO:log ex
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您还可以考虑通过在 global.aspx 中声明以下方法来处理AuthenticateRequest事件。

注意:Application_AuthenticateRequest事件在FormsAuthentication_OnAuthenticate事件之后触发。

void Application_AuthenticateRequest(object sender, EventArgs e)
{
    if (HttpContext.Current.User != null && HttpContext.Current.User.Identity.IsAuthenticated)
    {                
        MembershipUser user = Membership.GetUser();
        if (user == null)
        {
            FormsAuthentication.SignOut();
            HttpContext.Current.User = null;
        }
    }            
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助..