RedirectToAction causing empty cookie to be set ahead of cookie with values, which results in “lost” cookie

StackOverflow https://stackoverflow.com/questions/4157465

문제

I am using a cookie and if the cookie is set, it forwards the user to signin, else it shows them an error page (unauthorized). The cookie is being set correctly, and if I navigate to any page by typing it in the address bar, it works just fine. However, when I use RedirectToAction or FormsAuthentication.RedirectToLogin the cookie is not available, which is causing an infinite loop in redirection.

Home - If user has cookie, go to signin, if not show home page.

Signin - If user has cookie, show page, else redirect to home

My redirection is handled through an attribute.

public sealed class RequireBillerAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        IUserSession session = ServiceLocator.Locate<IUserSession>();

        if (session.BillerId == 0)
            filterContext.Result = new RedirectResult("~/");
    }
}

My Home action looks like this

    public ActionResult Index()
    {
        //if the user is signed in, send them to their account page.  They don't need to see the front page
        if (Request.IsAuthenticated)
        {          
            return RedirectToAction("Index", "Account");
        }

        //users with their cookie set should sign in
        if (session.BillerId != 0)
            return RedirectToAction("Index", "SignIn");

        return View();
    }

And my signin action looks like this

    [RequireBiller]
    public ActionResult Index()
    {
        SignInModel model = BuildSignInModel();

        return View(model);
    }

Now, when I hit mysite.com/ the redirect causes an infinite loop. In debugging, the attribute cannot find the value from the cookie. The cookie is actually blank in the request. When I type mysite.com/signin everything works peachy. Any ideas?

EDIT

As suggested, I ran fiddler. Here's what the requests look like

#   Result  Protocol    Host    URL Body    Caching Content-Type    Process Comments    Custom  
1   302 HTTP    localhost:27412 /   124 private     text/html; charset=utf-8    chrome:6008         
2   302 HTTP    localhost:27412 /SignIn 118 private     text/html; charset=utf-8    chrome:6008         
3   302 HTTP    localhost:27412 /   124 private     text/html; charset=utf-8    chrome:6008         
4   302 HTTP    localhost:27412 /SignIn 118 private     text/html; charset=utf-8    chrome:6008 

And here is the cookie information

First

__RequestVerificationToken_Lw__=NNu8v2oTMX2YKQOW+JRN1LQRYPhlmPszQa8Rs1KrQp1pPxWmQO8GG7eRrzbhFZF38p05ckuLHAK3QaTIlxeFJ6POTX1woXRx/ahApLpF529inJO9mj3jSnoHqG6fthzJpoLYQL61NOCCUO2wwzLmQg==; 4%40f0nkyBbqcTD4g9yl1J8KDNcWdqRpixrEoHLuMP2Lc*=P%2ffJD5CdLO0pCGU6GntaPw*=P6QAytlDVUrkQn84c9vDVg*

Second

4%40f0nkyBbqcTD4g9yl1J8KDNcWdqRpixrEoHLuMP2Lc*=; __RequestVerificationToken_Lw__=NNu8v2oTMX2YKQOW+JRN1LQRYPhlmPszQa8Rs1KrQp1pPxWmQO8GG7eRrzbhFZF38p05ckuLHAK3QaTIlxeFJ6POTX1woXRx/ahApLpF529inJO9mj3jSnoHqG6fthzJpoLYQL61NOCCUO2wwzLmQg==; 4%40f0nkyBbqcTD4g9yl1J8KDNcWdqRpixrEoHLuMP2Lc*=P%2ffJD5CdLO0pCGU6GntaPw*=P6QAytlDVUrkQn84c9vDVg*

Third

__RequestVerificationToken_Lw__=NNu8v2oTMX2YKQOW+JRN1LQRYPhlmPszQa8Rs1KrQp1pPxWmQO8GG7eRrzbhFZF38p05ckuLHAK3QaTIlxeFJ6POTX1woXRx/ahApLpF529inJO9mj3jSnoHqG6fthzJpoLYQL61NOCCUO2wwzLmQg==; 4%40f0nkyBbqcTD4g9yl1J8KDNcWdqRpixrEoHLuMP2Lc*=P%2ffJD5CdLO0pCGU6GntaPw*=P6QAytlDVUrkQn84c9vDVg*

Fourth

4%40f0nkyBbqcTD4g9yl1J8KDNcWdqRpixrEoHLuMP2Lc*=; __RequestVerificationToken_Lw__=NNu8v2oTMX2YKQOW+JRN1LQRYPhlmPszQa8Rs1KrQp1pPxWmQO8GG7eRrzbhFZF38p05ckuLHAK3QaTIlxeFJ6POTX1woXRx/ahApLpF529inJO9mj3jSnoHqG6fthzJpoLYQL61NOCCUO2wwzLmQg==; 4%40f0nkyBbqcTD4g9yl1J8KDNcWdqRpixrEoHLuMP2Lc*=P%2ffJD5CdLO0pCGU6GntaPw*=P6QAytlDVUrkQn84c9vDVg*

And here's what it looks like when I type in /signin into the address bar

__RequestVerificationToken_Lw__=NNu8v2oTMX2YKQOW+JRN1LQRYPhlmPszQa8Rs1KrQp1pPxWmQO8GG7eRrzbhFZF38p05ckuLHAK3QaTIlxeFJ6POTX1woXRx/ahApLpF529inJO9mj3jSnoHqG6fthzJpoLYQL61NOCCUO2wwzLmQg==; 4%40f0nkyBbqcTD4g9yl1J8KDNcWdqRpixrEoHLuMP2Lc*=P%2ffJD5CdLO0pCGU6GntaPw*=P6QAytlDVUrkQn84c9vDVg*

Yes, my cookies are encrypted. The cookiename is "4%40f0nkyBbqcTD4g9yl1J8KDNcWdqRpixrEoHLuMP2Lc*" It seems to me the redirect is appending a new empty cookie in there. WHY? I'm not sure.

ADDITIONAL After debugging, I have found that indeed there are 3 cookies in the Request. The first is the empty cookie, which is returned by default when using the name. The third cookie in the collection has the values set. Why it is appending this cookie into the request is a mystery. I can probably work around this by picking the cookie that has a value over the other one, but I'd rather fix the root issue, whatever it is, that is happening only on the signin page.

도움이 되었습니까?

해결책

I think what's happening is that RedirectToAction is doing a Response.Redirect() which is terminating the processing of the request and not allowing the cookie to be set. Sounds like a similar problem to what is documented here for session:

http://weblogs.asp.net/bleroy/archive/2004/08/03/207486.aspx

다른 팁

I had a cookie that was not being set properly after calling RedirectToAction(). I ended up utilizing TempData[] as described in this answer: https://stackoverflow.com/a/3624353/1265197

Here is my code. The account string was retrieved via a Query String on the url named 'account':

public ActionResult OriginatingAction(string account)
{
    //Some other code
    TempData["data"] = account; 

    return RedirectToAction("RedirectAction");
}

I could then use TempData["data"] to set the cookie in the action that I redirected to:

public ActionResult RedirectAction()
{
    if(TempData["data"] != null)
    {
        HttpCookie dataCookie = new HttpCookie("dataCookie");
        dataCookie.Values.Add("account", TempData["data"] as string);
        dataCookie.Expires = DateTime.Now.AddHours(12);
        Response.Cookies.Add(dataCookie);
    }

    return View();
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top