【发布时间】:2013-07-02 16:59:08
【问题描述】:
我正在使用 Visual Studio 2012 开发带有 WPF (.NET 4.0) 客户端的 ASP WebAPI (ASP MVC 4) 应用程序。客户端需要登录到服务器。我使用 FormsAuthentication 和身份验证 cookie 来登录。登录在 ASP MVC 中已经可以正常工作了。
问题是,虽然登录在服务器上成功执行并且cookie被发送回客户端,但cookie在随后的调用中没有发送到服务器,即使CookieContainer与auth一起使用cookie 集。
下面是简化版的代码:
客户
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/”来查看本地流量)。然后我怀疑fiddler可能会干扰,所以我只是用Visual Studio 2012调试。
我已经尝试和验证的内容:
通过登录方法到达服务器
使用客户端发送的数据成功验证用户身份
cookie 设置在服务器上
cookie 在响应中(用 fiddler 验证)
操作后cookie在CookieContainer中。这里有一个奇怪的地方:容器中cookie的域设置为“localhost”(用VS2012调试器验证)。 不应该是“
http://localhost:50000”吗?当我尝试使用cookieContainer.GetCookies(new Uri("http://localhost:50000"))获取容器的 cookie 时,它什么也不返回。当我使用cookieContainer.GetCookies(new Uri("localhost"))尝试它时,它给了我一个无效的 Uri 错误。不知道这里发生了什么。在发出
PostItem请求之前,cookie 就在容器中。当到达httpClient.PostAsJsonAsync语句时,在HttpClient 中正确设置了容器。cookie 没有发送到服务器(我用 fiddler 和 Global.asax.cs 中的
Application_PostAuthenticateRequest方法检查过,验证了this.Request.Cookies)
我怀疑由于CookieContainer 中的域不匹配而没有发送cookie,但是为什么首先没有在CookieContainer 中设置域?
【问题讨论】:
-
你能从 fiddler 中展示 cookie 的样子吗? 'new Uri("localhost")' 无效,因为您指定的是相对 URI,但没有说它是相对的。试试新的 Uri("localhost")。
-
另外,你真的不应该在每个请求上重新创建 HttpClient。将其存储为字段并重复使用相同的实例。
-
尝试在返回响应之前在 web.api 登录控制器中将 cookie 路径显式设置为“/”。这个我没有测试过,但是有可能是如果不设置路径就添加cookie的话,会默认为当前请求的路径。如果是这种情况,它将解释为什么 cookie 没有在以下请求中发送到不同的路径。
标签: asp.net cookies asp.net-web-api