2

设想

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

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

问题

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

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

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

我想做的事

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

MembershipUser user = Membership.GetUser();
if(user == null) {
    FormsAuthentication.SignOut();
}

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

另外,我什至不确定这是做事的正确方法。如果不是,那么在仅取决于我目前的会员类别之前,确保身份验证 cookie 适用于有效用户的最佳方法是什么?

4

2 回答 2

4

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

public void FormsAuthentication_OnAuthenticate(object sender, FormsAuthenticationEventArgs args)
{ 
}

编辑:

上述方法中,Membership.GetUser()将返回null,因为它从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
        }
    }
}

您还可以考虑通过在 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;
        }
    }            
}

希望这可以帮助..

于 2012-05-02T19:19:26.617 回答
0

您创建一个覆盖 的基本控制器OnActionExecuting并将您的代码放在那里。让您的所有控制器控制器都从他那里继承。这是 OnActionExecuting我的一个旧项目

protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
    if (Request.IsAuthenticated)
    {
        if (Session[SomeKey] == null)
        {
            filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary { { "controller", "Account" }, { "action", "LogOff" } });
        }
    }
    base.OnActionExecuting(filterContext);
}

我基本上是在检查请求是否经过身份验证,否则我会将其重定向到注销操作。 http://msdn.microsoft.com/en-us/library/system.web.mvc.controller.onactionexecuting.aspx

于 2012-05-02T22:32:51.460 回答