I am working in two projects. One is using ASP.NET MVC and another one is using ASP.NET WebAPI. Our client wants to implement load balancing but they're concerned that once it is done, it may affect the login feature, as user's authentication token may not be shared among the servers. I am assigned to research on this issue. Can anyone please tell me is it possible to synchronise and share user's login status and authentication token among the servers for load-balancing purpose? If so, how? Here is the code of Login function in ASP.NET WebAPI project.
public async Task<IHttpActionResult> Login(LoginModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// Invoke the "token" OWIN service to perform the login (POST /api/token)
var requestParams = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("client_id", APP_CLIENT_ID),
new KeyValuePair<string, string>("username", model.Username),
new KeyValuePair<string, string>("password", model.Password)
};
var requestParamsFormUrlEncoded = new FormUrlEncodedContent(requestParams);
var baseUrl = apiConfiguration.Host;
var getTokenUrl = $"{baseUrl}/token";
var tokenServiceResponse = await httpClient.PostAsync(getTokenUrl, requestParamsFormUrlEncoded);
if (!tokenServiceResponse.IsSuccessStatusCode)
{
// Log response
if (tokenServiceResponse.StatusCode == HttpStatusCode.NotFound)
{
log.ErrorFormat("Can not get token from url: {0}", getTokenUrl);
return BadRequest(SERVER_ERROR_MESSAGE);
}
else
{
string content = await tokenServiceResponse.Content.ReadAsStringAsync();
if (tokenServiceResponse.StatusCode == HttpStatusCode.InternalServerError)
{
log.Error(content);
return BadRequest(SERVER_ERROR_MESSAGE);
}
else
{
log.InfoFormat("Get token fail request fail | RESPONE - StatusCode: {0} - Reason: {1} - Content: {2}", tokenServiceResponse.StatusCode, tokenServiceResponse.ReasonPhrase, content);
return BadRequest(INVALID_USER_DATA_MESSAGE);
}
}
}
var result = ResponseMessage(tokenServiceResponse);
var user = await userManager.FindByNameAsync(model.Username);
if (user == null || user.IsDeleted)
{
log.InfoFormat("Invalid user data. Username: {0}", model.Username);
return BadRequest(INVALID_USER_DATA_MESSAGE);
}
else if (user.AccountBlocked == true)
{
log.InfoFormat("The account {0} is blocked", model.Username);
return BadRequest(ACCOUNT_IS_BLOCKED_MESSAGE);
}
var userId = user.Id;
accountNotificationService.LogIn(userId, result.Response.IsSuccessStatusCode, APP_CLIENT_ID);
return result;
}
And this is the code of the Login function in ASP.NET MVC project.
public async Task<IHttpActionResult> Login(LoginModel model)
{
if (model == null)
{
return this.BadRequest("Invalid user data");
}
// Invoke the "token" OWIN service to perform the login (POST /api/token)
var requestParams = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("client_id", APP_CLIENT_ID),
new KeyValuePair<string, string>("username", model.Username),
new KeyValuePair<string, string>("password", model.Password)
};
try
{
var requestParamsFormUrlEncoded = new FormUrlEncodedContent(requestParams);
var tokenServiceResponse = await new HttpClient().PostAsync(
string.Format("{0}/Token", Config.Application.Host), requestParamsFormUrlEncoded);
var result = this.ResponseMessage(tokenServiceResponse);
if (!result.Response.IsSuccessStatusCode)
{
return this.BadRequest("Credentials are incorrect");
}
var user = result.Response.IsSuccessStatusCode ? await accountService.FindUser(model.Username, model.Password) : null;
if (user == null)
{
return this.BadRequest("Credentials are invalid");
}
else if (user.IsDeleted)
{
return this.BadRequest("This user does not exists");
}
if (user.AccountBlocked == true)
{
return this.BadRequest("This account is blocked");
}
notificationService.LogIn(user?.Id, result.Response.IsSuccessStatusCode, APP_CLIENT_ID);
return result;
}
catch (Exception ex)
{
ErrorLogging.LogError(ex, "Error in Login");
return BasicResponse(new ResultModel
{
Success = false,
ResponseCode = System.Net.HttpStatusCode.InternalServerError,
Message = Constants.ErrorMessageCategory.General
});
}
}