简体   繁体   English

表单身份验证和身份验证Cookie不持久

[英]Forms Authentication and authentication cookie not persisting

aware that there are a lot of questions relating to Forms Authentication and the persistence of cookies, but having spent most of a day delving around, I'm still having difficulties. 我知道有很多与表单身份验证和cookie持久性有关的问题,但是花了整整一天的时间在研究,我仍然遇到困难。

My Problem 我的问题

I am working on a web app (VS2010 but webapp is f/w 3.5) which restricts access to certain parts of the app to authenticated users (whereas other parts are open). 我正在使用一个Web应用程序(VS2010,但WebApp是f / w 3.5),该应用程序将对身份验证用户的应用程序某些部分的访问权限限制为打开(而其他部分则处于打开状态)。 My problem is that my authentication cookies do not appear to be persisting after I close the browser. 我的问题是我关闭浏览器后,身份验证cookie似乎没有持久化。

My Approach 我的方法

I have written a simple login.aspx page which is configured in web.config as follows: 我编写了一个简单的login.aspx页面,该页面在web.config中进行了如下配置:

<authentication mode="Forms">

...and the individual pages' behaviour are declared like so: ...并且各个页面的行为声明如下:

<location path="ClientManageAccount.aspx">
     <system.web>
        <authorization>
           <deny users="?" />
        </authorization>
     </system.web>
</location>

...which works fine in every respect EXCEPT for these cookie shenanigans... ...除了这些cookie恶作剧外,在各个方面都可以正常工作...

I create the authentication cookie manually once I have authenticated my user's login & password against the database (which works fine) in the login.aspx page. 一旦我在login.aspx页中针对数据库对用户的登录名和密码进行了身份验证(正常工作),便会手动创建身份验证cookie。 If the user selects the 'keep me logged in' checkbox, the cookie is generated using this method: 如果用户选中“保持登录状态”复选框,则使用以下方法生成Cookie:

    private void GenerateAuthenticationCookie(int expiryInMinutes, Guid userGuid)
    {
        DateTime cookieExpiration = DateTime.Now.AddMinutes(expiryInMinutes); // change to months for production
        var authenticationTicket =
            new FormsAuthenticationTicket(
                2,
                userGuid.ToString(), 
                DateTime.Now,
                cookieExpiration,
                true, 
                string.Empty,
                FormsAuthentication.FormsCookiePath);

        // ticket must be encrypted
        string encryptedTicket = FormsAuthentication.Encrypt(authenticationTicket);

        // create cookie to contain encrypted auth ticket
        var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
        authCookie.Expires = authenticationTicket.Expiration;
        authCookie.Path = FormsAuthentication.FormsCookiePath;

        // clear out existing cookie for good measure (probably overkill) then add
        HttpContext.Current.Response.Cookies.Remove(FormsAuthentication.FormsCookieName); 
        HttpContext.Current.Response.Cookies.Add(authCookie);
    }

The objective here is that I store a user Guid in the auth cookie, which I will then use to restore a user object into session (this is also in the login.aspx page, and my thinking is that I'd like to pluck the user guid from the auth cookie that I have created, and use it to stuff the corresponding user record into session and redirect to the requested page): 这里的目的是我将用户Guid存储在auth cookie中,然后将其用于将用户对象还原到会话中(这也位于login.aspx页面中,我的想法是我希望摘下我创建的auth cookie中的用户guid,并使用它来将相应的用户记录填充到会话中并重定向到请求的页面):

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            TryAutoLogin();
        }            
    }

    private void TryAutoLogin()
    {
        HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(FormsAuthentication.FormsCookieName);

        if (cookie != null)
        {
            FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);

            if (ticket != null)
            {
                if (ticket.Name.Length > 0)
                {
                    try
                    {
                        Guid userGuid = new Guid(ticket.Name);
                        KUser user = UserFunctions.GetUserFromUserGuid(userGuid);

                        if (user != null) Session["User"] = user;

                        FormsAuthentication.RedirectFromLoginPage(userGuid.ToString(), true);
                    }
                    catch (Exception anyException)
                    {
                        // don't do anything for now - do something smart later :-)                        }
                }
            }
        }
    }

Finally, here is the code for the login button on my login.aspx page: 最后,这是我的login.aspx页面上的登录按钮的代码:

    protected void Submit_OnClick(object sender, EventArgs e)
    {
        long userId = 0;
        UserAuthenticationStatus status;

        status = (UserAuthenticationStatus)UserFunctions.UserAuthenticates(EmailAddress.Text, Password.Text, ref userId);

        switch (status)
        {
            case UserAuthenticationStatus.Authenticated:
                //email address and password match, account ok, so log this user in
                KUser user = UserFunctions.GetUser(userId);
                Session["User"] = user;

                if (ChkRememberMe.Checked)
                {
                    GenerateAuthenticationCookie(15, user.UserGuid); // 15 minutes

                    FormsAuthentication.RedirectFromLoginPage(user.UserGuid.ToString(), true);
                }
                else
                {
                    FormsAuthentication.RedirectFromLoginPage(user.UserGuid.ToString(), false);
                }
                break;
            case UserAuthenticationStatus.AuthButLocked:
                // email/pwd match but account is locked so do something
                ShowLockedAccountMessage();
                break;
            case UserAuthenticationStatus.EmailFoundIncorrectPassword:
            case UserAuthenticationStatus.EmailNotFound:
            case UserAuthenticationStatus.Unknown:
                // either the email wasn't found, or the password was incorrect or there was some other problem
                // present message stating this and offer chance to register
                ShowFailedLoginMessage();
                break;
            default:
                ShowUnavailableMessage();
                break;
        }
    }

As you can see, there's nothing particularly complex going on, but despite the fact that the authCookie which is created in GenerateAuthenticationCookie(..) being created correctly (as far as I can tell) it does not persist. 如您所见,没有什么特别复杂的事情发生,但是尽管在GenerateAuthenticationCookie(..)中创建的authCookie被正确创建了(据我所知),它并没有持久存在。

One thing I have noticed is that if I place some code into the Application_AuthenticateRequest method in global.asax.cs, such as: 我注意到的一件事是,如果将一些代码放入global.asax.cs的Application_AuthenticateRequest方法中,例如:

    protected void Application_AuthenticateRequest(object sender, EventArgs e)
    {
        HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(FormsAuthentication.FormsCookieName);

        if (cookie != null)
        {
            int x = 4;  // just a dummy line so that I can set a breakpoint
        }
    }

...that breakpoint is sometimes hit following a new browser session, although it stops being hit once I navigate away from the startup page (in this case a dummy start.aspx page used purely for dev & testing). ...这个断点有时会在新的浏览器会话之后被命中,尽管一旦我离开启动页面(在本例中为纯start.aspx页面仅用于开发和测试),它就会不再被命中。

So, apologies for the long question, but I'm truly suffering here. 因此,对这个长期的问题表示歉意,但是我在这里确实感到很痛苦。

Things I have checked/tried 我检查过/尝试过的事情

Ensuring that the code is being executed - YES Browser settings - ie no deletion of cookies on exit - CONFIRMED NO DELETION Trying different timeouts - eg equal or different to the web.config timeout, doesn't seem to matter... ...and of course at least twenty or thirty different previous questions, but to no avail. 确保代码正在执行-是浏览器设置-即退出时不删除cookie-确认否删除尝试不同的超时-例如等于或不同于web.config超时,似乎没有关系... ...当然,至少有20或30个先前的不同问题,但无济于事。

System/Dev Environment 系统/开发环境

Windows 7 64-bit, VS2010 (but proj is a 3.5), SQL Server 2008 Express. Windows 7 64位,VS2010(但proj为3.5),SQL Server 2008 Express。

On my dev server, this problem remains so I'm not sure it's necessarily environmental - that machine is a WS2008R2 box running SQL 2008R2 - and the same problem remains. 在我的开发服务器上,此问题仍然存在,因此我不确定这是否一定是环境问题-该机器是运行SQL 2008R2的WS2008R2机器-仍然存在相同的问题。

Does anyone, anywhere, have any ideas for things I can try here? 是否有人在任何地方对我可以在这里尝试的东西有任何想法? I have a hunch I could get this working by intercepting the initial Application_AuthenticateRequest hit in global.asax.cs and stuffing something into session state to mark as 'authenticated' (to avoid an expensive authentication attempt every time that method is called, which turns out to be several times per page. 我有一种预感,可以通过拦截global.asax.cs中最初的Application_AuthenticateRequest命中并将某些内容塞入会话状态以标记为“已认证”(以避免每次调用该方法时进行昂贵的身份验证尝试)来使其工作每页几次。

Thanks in advance, 提前致谢,

John 约翰

OK, having spent all that time writing that, I had a moment of clarity and realised that (a) I didn't need to be doing any of that checking on the Page_Load() as (if this were working properly) the login.aspx page wouldn't be called at all, and (b) I ought to have been able to get to the cookie from the Session_Start - which is where I relocated the TryAutoLogin code. 好了,花了所有的时间写这些,我花了一会儿时间,意识到(a)我不需要对Page_Load()进行任何检查,就像(如果它能正常工作)登录一样。 aspx页面根本不会被调用,并且(b)我应该能够从Session_Start到达cookie-这是我重新放置TryAutoLogin代码的地方。

This in itself was a step forward, but despite retrieving the cookie and therefore the user guid from it, I found that by I was still getting punted back to the login.aspx page. 这本身是向前迈出的一步,但是尽管检索了cookie并因此从中获取了用户的指导,但我发现到那时我仍然被引回了login.aspx页面。

It was at this point I recalled the fact that I have a parent master page and two child master pages - one which I set for non-authentication pages (eg homepage) and one for those pages requiring authentication. 正是在这一点上,我想起了一个事实,即我有一个父母版页和两个子母版页-我为非身份验证页(例如,主页)设置了一个,为那些需要身份验证的页设置了一个。 I vaguely recalled a problem with session timeouts and had placed the following code in the OnInit override: 我隐约想起了会话超时问题,并将以下代码放在OnInit覆盖中:

       if (Session["User"] == null)
       {
              FormsAuthentication.SignOut();
              FormsAuthentication.RedirectToLoginPage();
              Response.End();
       }

...which in itself wasn't so bad (and avoided a nasty bug on timeouts) but also on the start.aspx page, I found this gem: ...本身并不算太糟糕(并避免了超时时的讨厌错误),但在start.aspx页面上,我发现了这个宝石:

Session.Clear();

...in the Page_Load! ...在Page_Load中!

So, what was happening was that I was inadvertently clearing the session into which I had placed my newly recovered user record. 因此,发生的事情是我无意中清除了将新恢复的用户记录放入的会话。 Which meant that the authorisation master page's OnInit override was then detecting the absence of the user object and - ta dah! 这意味着授权母版页的OnInit覆盖随后将检测到用户对象的缺失,并且-ta dah! - signing the user out, which in turn removes the authorisation cookie... -注销用户,依次删除授权cookie ...

So, a bit of wiring and some sleuthing later, and I can put this one to bed. 因此,稍作布线,稍后再进行侦探,我可以把它放在床上。

Thanks for reading (even if I did figure it out on my own)... :) 感谢您的阅读(即使我自己弄清楚了)... :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM