Reputation: 1947
I have an API in .NET Core which source code is available here. Now I'm building an MVC application which uses that API. The problem is about CookieAuthentication system in the API.
I have this code in my Configure
method in Startup.cs
:
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
AuthenticationScheme = "CookieAuthentication",
LoginPath = new PathString("/users/login"),
AutomaticAuthenticate = true,
AutomaticChallenge = true
});
In my login method (HttpPost) I set my cookie like this:
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, request.Email)
};
var userIdentity = new ClaimsIdentity(claims, "login");
ClaimsPrincipal principal = new ClaimsPrincipal(userIdentity);
await HttpContext.Authentication.SignInAsync("CookieAuthentication", principal);
return StatusCode(302);
Then in every method which requires authorization I check if user is logged in like this:
if (email != await GetLoggedUserEmail())
{
throw new ServiceException(ErrorCodes.UserNotFound, "You can only edit information on your account.");
}
// do some logic
...
public async Task<string> GetLoggedUserEmail()
{
if (HttpContext.User.Identity.Name == null)
{
throw new ServiceException(ErrorCodes.UserNotFound, "There is no logged in user.");
}
return await Task.FromResult(HttpContext.User.Identity.Name);
}
The problem is that when I log in by using for example Fiddler for requests and then try to delete some information by the HttpDelete request the cookie authentication works correct (I can only edit or delete informations about myself. I can't edit or delete not mine information because it will check that I'm the wrong logged user to do that. That's great.).
But when I try to do it in my MVC application strange thing happens. When I login in the API like this:
using (var client = new HttpClient())
{
var content = new StringContent(JsonConvert.SerializeObject(values), Encoding.UTF8, "application/json");
var response = await client.PostAsync("http://www.pets.pawelkowalewicz.pl/users/login", content);
}
Then my response.StatusCode
is 302 (which is correct according to the API). And then when I try to delete some information on the other page using this request:
using (var client = new HttpClient())
{
var response = await client.DeleteAsync("http://www.pets.pawelkowalewicz.pl/users/[email protected]/Animals/aaa");
}
Then response.StatusCode
is 400! Seems like the cookie that I'm logged in expired or something...
But when I try to execute this request right after I login like this:
var response = await client.PostAsync("http://www.pets.pawelkowalewicz.pl/users/login", content);
var response2 = await client.DeleteAsync("http://www.pets.pawelkowalewicz.pl/users/[email protected]/Animals/aaa");
Response2.StatusCode
is correct and the information is deleted. I really don't know why it is happening.
Seems like this is some problem that occurres while I'm redirecting throught few pages before I try to execute delete request. When I do it right after login request in the same method it works fine.
Please help me with this problem.
Upvotes: 0
Views: 124
Reputation: 3208
The problem is that HttpClientHandler
instance is storing cookies inside CookieContainer
and you are not sharing the container.
You may want to create shared CookieContainer
instance.
private static readonly cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
{
using (var client = new HttpClient(handler))
{
// Do your work here
}
}
Or after successful login extract cookies from handler.
using (var client = new HttpClient())
{
var content = new StringContent(JsonConvert.SerializeObject(values), Encoding.UTF8, "application/json");
var response = await client.PostAsync("http://www.pets.pawelkowalewicz.pl/users/login", content);
CookieCollection cookies = client.Handler.CookieContainer.GetCookies("http://www.pets.pawelkowalewicz.pl/");
// Store cookies collection somewhere it suits you
}
Then add to new instance of CookieContainer
each time you instantiate new HttpClient
.
CookieContainer cookieContainer = new CookieContainer();
CookieCollection cookies = LoadCookiesFromSomewhereYouStoredIt();
cookieContainer.Add("http://www.pets.pawelkowalewicz.pl/", cookies);
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
{
using (var client = new HttpClient(handler))
{
// Do your work here
}
}
Upvotes: 1