Can't set FormsAuthenicationTicket.UserData in

2019-05-17 02:18发布

问题:

I'm trying to implement the "Writing Information to UserData" section of this article, but it doesn't work properly when the cookie is part of the URI.

My code:

// Create the cookie that contains the forms authentication ticket
HttpCookie authCookie = FormsAuthentication.GetAuthCookie( userName, createPersistantCookie );

// Get the FormsAuthenticationTicket out of the encrypted cookie
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt( authCookie.Value );

// Create a new FormsAuthenticationTicket that includes our custom User Data
FormsAuthenticationTicket newTicket = new FormsAuthenticationTicket( ticket.Version, ticket.Name, ticket.IssueDate, ticket.Expiration, ticket.IsPersistent, "foo");

// Update the authCookie's Value to use the encrypted version of newTicket
authCookie.Value = FormsAuthentication.Encrypt( newTicket );

// Manually add the authCookie to the Cookies collection
HttpContext.Current.Response.Cookies.Add( authCookie );

// Determine redirect URL and send user there
string redirUrl = FormsAuthentication.GetRedirectUrl( userName, createPersistantCookie );

HttpContext.Current.Response.Redirect( redirUrl, false );

When cookieless is used, the page redirects but doesn't get the correct URI with the cookie information in it, so it loops back to my Login page where Request.IsAuthenticated returns false. An endless loop ensues.

How do I redirect to the proper URI?

回答1:

I found this to be an interesting problem, so I set about doing some digging, testing, and a little bit of debugging into the .net framework source.

Basically, what you are trying to do will not work. Anything you put into the Response.Cookies collection will just be ignored if the browser doesn't support cookies. You can check Request.Browser.Cookies to see if cookies are supported.

In asp.net, both session state and authentication support a cookieless mode, but this does not extend to other cookies. In fact, it seems that session and authentication can be set to different modes of operation themselves even.

The authentication system can store it's own data in the URI, but it does so by directly manipulating the URI itself. Sadly, Microsoft doesn't appear to have exposed these capabilities to code outside the authentication module.

Basically, if you use the methods like FormsAuthentication.GetAuthCookie() and FormsAuthentication.SetAuthCookie() then the authentication system will take care of putting that information into the URI for you automagically... but it doesn't allow you to supply a customized authentication ticket to these methods... so you are stuck with the default auth ticket.In these cases, you are on your own for storing any custom data.

Anyway...

There really isn't much advantage to storing custom data directly in an authentication ticket if the authentication system has gone cookieless... in cookieless mode, things like "persistant cookie" have no meaning so you'll be regenerating the data at least once per session anyway.

The most common suggestion for cases where you are cookieless but still need custom data like this is to enable cookieless sessions, and just store your custom data as a session variable. The session ID will get put into the URI, but the custom data will stay in memory on the server. The usage pattern is identical no matter if your sessions are cookieless or not.

If you really wanted to, you could come up with a system of storing the custom data in the URI manually. The easiest thing to do would be to put the custom data into query strings or use pathdata. I can't see any real advantage to this over sessions variables unless you are just deperate not to use server memory (adding a little memory to a server is cheap, ugly URLs and manually writing code to deal with them is not cheap).



回答2:

Thank you for the great explanation, Stephen. In cases where the user does not allow cookies, I'm just going to have to avoid the UserData and load the data from the database.

Before the code listed above I'll do:

if( !HttpContext.Current.Request.Browser.Cookies || !FormsAuthentication.CookiesSupported )
{
    FormsAuthentication.RedirectFromLoginPage( userName, false);
    return;
}