HttpClient的不从的CookieContainer发送cookie [英] HttpClient does not send cookies from CookieContainer

查看:1201
本文介绍了HttpClient的不从的CookieContainer发送cookie的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个WPF(.NET 4.0)客户端ASP的WebAPI(ASP MVC 4)应用程序,使用Visual Studio 2012的客户端需要登录到服务器。我使用FormsAuthentication与身份验证cookie登录。登录已在ASP MVC正常工作。

I'm developing a ASP WebAPI (ASP MVC 4) application with a WPF (.NET 4.0) client, using Visual Studio 2012. The client needs to login to the server. I use FormsAuthentication with an authentication cookie to login. The login already works fine in ASP MVC.

的问题是,虽然登录被成功地在服务器上执行并且该cookie被发送回客户端,该cookie不后续调用服务器发送,即使的CookieContainer 重复使用的身份验证cookie的设定。

The problem is that, although the login is sucessfully executed on the server and the cookie is sent back to the client, the cookie is not sent in subsequent calls to the server, even though the CookieContainer is reused with the auth cookie set.

下面是code的简化版本:

Here is a simplified version of the code:

客户端

public async Task<UserProfile> Login(string userName, string password, bool rememberMe)
{           
    using (var handler = new HttpClientHandler() { CookieContainer = this.cookieContainer })
    using (var httpClient = new HttpClient(handler))
    {
        httpClient.BaseAddress = new Uri("http://localhost:50000/");

        httpClient.DefaultRequestHeaders.Accept.Add(
            new MediaTypeWithQualityHeaderValue("application/json"));

        var result = await httpClient.PostAsJsonAsync("api/auth/login", new
        {
            username = userName,
            password = password,
            rememberMe = rememberMe
        });

        result.EnsureSuccessStatusCode();

        var userProfile = await result.Content.ReadAsAsync<UserProfile>();

        if (userProfile == null)
            throw new UnauthorizedAccessException();

        return userProfile;
    }
}

public async Task<ExamSubmissionResponse> PostItem(Item item)
{
    using (var handler = new HttpClientHandler() { CookieContainer = this.cookieContainer })
    using (var httpClient = new HttpClient(handler))
    {
        httpClient.BaseAddress = new Uri("http://localhost:50000/");

        var result = await httpClient.PostAsJsonAsync("api/Items/", item);
    }
}

服务器

[HttpPost]
public HttpResponseMessage Login(LoginModel model)
{
    if (this.ValidateUser(model.UserName, model.Password))
    {
        // Get user data from database

        string userData = JsonConvert.SerializeObject(userModel);

        var authTicket = new FormsAuthenticationTicket(
            1,
            model.UserName,
            DateTime.Now,
            DateTime.Now.AddMinutes(10 * 15),
            model.RememberMe,
            userData
        );              

        string ticket = FormsAuthentication.Encrypt(authTicket);
        var cookie = new CookieHeaderValue(FormsAuthentication.FormsCookieName, ticket);
        var response = Request.CreateResponse(HttpStatusCode.Created, userModel);
        response.Headers.AddCookies(new CookieHeaderValue[] { cookie });

        return response;
    }
    return null;
}

首先,我使用调试的Fiddler2问题(我用的基地址为 HTTP://localhost.fiddler:50000 / 查看本地流量)。然后,我怀疑提琴手可能会干扰,所以我只是与Visual Studio 2012进行调试。

First I debugged the problem using Fiddler2 (I used the base address as "http://localhost.fiddler:50000/" to view local traffic). Then I suspected that fiddler might be interfering, so I just debugged with Visual Studio 2012.

我曾尝试和验证:


  • 服务器通过登录方法达到

  • The server is reached by the Login method

用户被成功地从客户端发送的数据验证

The user is sucessfully authenticated with the data sent from the client

该Cookie在服务器上设置

The cookie is set on the server

该cookie是在响应(使用Fiddler验证)

The cookie is in the response (verified with fiddler)

该cookie是在的CookieContainer手术后。这里有一个奇怪的事情:在容器中的cookie的域设置为本地主机(与VS2012调试验证)。 难道不应该是的http://本地主机:50000 ?当我尝试使用 cookieContainer.GetCookies得到容器的饼干(新的URI(HTTP://本地主机:50000))将没有返回值。当我尝试它使用 cookieContainer.GetCookies(新的URI(本地主机))它给了我一个无效的Uri错误。不知道是怎么回事。

The cookie is in the CookieContainer after the operation. There is a strange thing here: the domain of the cookie in the container is set as "localhost" (verified with VS2012 debugger). Shouldn't it be "http://localhost:50000" ? When I try to get the cookies of the container using cookieContainer.GetCookies(new Uri("http://localhost:50000")) it returns nothing. When I try it using cookieContainer.GetCookies(new Uri("localhost")) it gives me an invalid Uri error. Not sure what's going on here.

该cookie是在 PostItem 发出请求之前的容器。容器被正确HttpClient的时候语句 httpClient.PostAsJsonAsync 在达到设定。

The cookie is in the container just before the PostItem request is made. The container is correctly set in the HttpClient when the statement httpClient.PostAsJsonAsync is reached.

该cookie不会被发送到服务器(我小提琴手,并在Global.asax.cs中的 Application_PostAuthenticateRequest 方法检查了它,核实 this.Request.Cookies

The cookie is not sent to the server (I checked it with fiddler and in the Application_PostAuthenticateRequest method in the Global.asax.cs, verifying this.Request.Cookies)

我怀疑cookie不会被发送,由于在域中不匹配的CookieContainer ,但为什么域没有设置,因为它应该在的CookieContainer <放在第一位/ code>?

I suspect the cookie is not being sent due to a domain mismatch in the CookieContainer, but why the domain is not set as it should in the CookieContainer in the first place?

推荐答案

您的问题是,你是不是对的设置从您的Web API控制器发送回Cookie,任何路径。

Your problem is that you are not setting any path on the cookie that you send back from your Web Api controller.

有控制在何处cookie发送两件事情:

There are two things that control where cookies are sent:


  1. cookie的域

  2. cookie的路径

关于域,共识似乎是,端口号将不再(但仍可能)在评估cookie域的一个因素。请参见这个问题关于端口号如何影响域的详细信息。

Regarding the domain, the consensus seems to be that the port number should no longer (but still might) be a factor in evaluating the cookie domain. See this question for more info about how port number affects the domain.

关于路径:Cookies是在其领域的特定路径相关。在你的情况下,Web API是发送一个cookie,而不指定它的路径。默认情况下,cookie将然后请求/响应创建该cookie的路径有关。

About the path: Cookies are associated with a specific path in their domain. In your case, the Web Api is sending a cookie without specifying it's path. By default the cookie will then be associated with the path of the request/response where the cookie was created.

在您的情况下,cookie将具有路径 API /认证/登录。这意味着该cookie将被发送到的子路径的(因为缺乏一个更好的词),这条道路的,但不是的兄弟的路径

In your case the cookie will have the path api/auth/login. This means the the cookie will be sent to child paths (for lack of a better term) of this path but not to parent or sibling paths.

要测试,请尝试:

cookieContainer.GetCookies(new Uri("http://localhost/api/auth/login")

这应该给你的cookie。所以,应该这样:

This should give you the cookie. So should this:

cookieContainer.GetCookies(new Uri("http://localhost/api/auth/login/foo/bar")

这些另一方面不会发现该Cookie:

These on the other hand will not find the cookie:

cookieContainer.GetCookies(new Uri("http://localhost/")
cookieContainer.GetCookies(new Uri("http://localhost/api/")
cookieContainer.GetCookies(new Uri("http://localhost/api/auth/")
cookieContainer.GetCookies(new Uri("http://localhost/api/auth/foo")
cookieContainer.GetCookies(new Uri("http://localhost/api/Items/")

要解决这个问题,简单地发送resonse前添加路径/(或者/ API)到cookie:

To fix the issue, simply add the path "/" (or perhaps "/api") to the cookie before sending the resonse:

...
string ticket = FormsAuthentication.Encrypt(authTicket);
var cookie = new CookieHeaderValue(FormsAuthentication.FormsCookieName, ticket);
cookie.Path = "/";
var response = Request.CreateResponse(HttpStatusCode.Created, userModel);
response.Headers.AddCookies(new CookieHeaderValue[] { cookie });
...

这篇关于HttpClient的不从的CookieContainer发送cookie的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆