views:

1144

answers:

2

I am using Form Authentication and sending an Aajx request to the server for authentication. Based on the json result, the client decides where to go and what to do. That is the reason I am not using FormsAuthentication.RedirectFromLoginPage to not interfere the ajax/json response.

In this case Request.IsAuthenticated returns false, even after validating the user with Membership.ValidateUser. Then I set the cookie using

FormsAuthentication.SetAuthCookie(username, false);

Although the second parameter, persistent cookie, is false, the cookie is still valid across browser sessions.

Any idea how to make Request.IsAuthenticated work without using FormsAuthentication.RedirectFromLoginPage?

+1  A: 

You need to update the current security principal for the request. When you call Response. Redirect(...) a new request is done and the security principal is reinitialized and Request.IsAuthenticated returns true in your case. FormsAuthentication.RedirectFromLoginPage internally calls Response. Redirect(...). You can manually renew the security principal for the current request like this:

public void RenewCurrentUser()
{
    System.Web.HttpCookie authCookie =
        System.Web.HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
    if (authCookie != null)
    {
        FormsAuthenticationTicket authTicket = null;
        authTicket = FormsAuthentication.Decrypt(authCookie.Value);

        if (authTicket != null && !authTicket.Expired)
        {
            FormsAuthenticationTicket newAuthTicket = authTicket;

            if (FormsAuthentication.SlidingExpiration)
            {
                newAuthTicket = FormsAuthentication.RenewTicketIfOld(authTicket);
            }
            string userData = newAuthTicket.UserData;
            string[] roles = userData.Split(',');

            System.Web.HttpContext.Current.User =
                new System.Security.Principal.GenericPrincipal(new FormsIdentity(newAuthTicket), roles);
        }
    }
}
Branislav Abadjimarinov
Manual renewal isn't required (especially for GenericPrincipal and FormsIdentity), and credentials shouldn't change part-way through a request, which why the cookie is added to the response and then a completely new response/request life cycle is performed. On the next request the cookie created by FormsAuthentication.SetAuthCookie() will be picked up.
Robert Paulson
Of course this method can be considered a hack because it doesn't follow the normal forms authentication flow. But it can be useful if you want to check if user is authenticated in the same request where authentication takes part.
Branislav Abadjimarinov
Sometimes though a hack is what you need - I was trying to do things "the right way" and forcing a redirect, and getting into a right state with other systems being redirected :(
Zhaph - Ben Duguid
+3  A: 

FormsAuthentication.SetAuthCookie

Method Creates an authentication ticket for the supplied user name and adds it to the cookies collection of the response, or to the URL if you are using cookieless authentication.

Ref: msdn

Have a look at the Forms Authentication Control Flow. The authentication cookie is set to the response cookie collection, and should be observable at the http protocol level (e.g. use FireCookie or Fiddler2 to verify this).

Membership only verifies a username/password. Neither Membership nor SetAuthCookie() will modify the current request. They expect to send the cookie back to the caller, and the next request is when the properties like IsAuthenticated will return true.

Note that you can override and extend these automatic processes using custom IIdentity and IPrincipal, and hook into the authentication events if you need to.

Also have a look at Using Forms Authentication with ASP.NET AJAX

Robert Paulson
This is a great answer.
Greg