I have a ASP.NET Core web application. Users can login, it uses Identity.
I am now building an Android app with Xamarin which will provide a very scaled down part of the site - adding/removing products from the inventory.
This is the login action:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
var result = await _signInManager.PasswordSignInAsync (model.Email, model.Password, model.RememberMe, lockoutOnFailure: true);
if (result.Succeeded)
{
var user = await UserManager.FindByNameAsync( model.Email );
if ( !user.IsApproved ) {
await _signInManager.SignOutAsync();
_logger.LogWarning(2, "User account not approved.");
return RedirectToAction("NotApproved");
}
AddAutoLogoutCookie();
_logger.LogInformation(1, "User logged in.");
return RedirectToLocal(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToAction("VerifyCode", new { Provider = AppSettings.GoogleAuthenticatorProviderName, ReturnUrl = returnUrl, RememberMe = model.RememberMe });
}
if (result.IsLockedOut)
{
_logger.LogWarning(2, "User account locked out.");
return View("Lockout");
}
else
{
ModelState.AddModelError(string.Empty, _localizer["Incorrect creds"]);
return View(model);
}
}
So, can I use this to log users into the Xamarin app? How would I approach this roughly? Thanks.
Your question is very broad but I will try help. If you have a website and a mobile application accessing the same database and using the same business logic I would recommend creating an API, your API should handle authentication and access to your Data layer and perform CRUD operations. It does not care what consumes it (a mobile app, or a website).
Your website and Mobile app will send requests to to this API and the API responds accordingly. to handle authorization you send a login and the API will return a Json Web token or cookie (depending on what you are using) and for subsequent requests you send this token with the request.
Using Xamarin a portable class library is a good place to handle consumption of the API as it can be reused on ios and android.
An example of what your Xamarin request could look like if you are using Json Web Tokens.
public async Task<HttpStatusCode> LoginAsync(CredentialModel credentialModel)
{
var uri = new Uri(UrlResourceNames.LoginUrl);
return await SendCredentialsAsync(credentialModel, uri);
}
private async Task<HttpStatusCode> SendCredentialsAsync(CredentialModel credentialModel, Uri uri)
{
var jsonProduct = JsonConvert.SerializeObject(credentialModel);
var httpContent = new StringContent(jsonProduct, Encoding.UTF8, "application/json");
var response = await _apiConnecter.PostRequest(uri, httpContent);
if (!response.IsSuccessStatusCode)
return response.StatusCode;
string responseJson = await response.Content.ReadAsStringAsync();
var tokenModel = JsonConvert.DeserializeObject<TokenModel>(responseJson);
Settings.JwtToken = tokenModel.Token;
Settings.JwtExpirationDate = tokenModel.Experation;
return response.StatusCode;
}
Then your APIConnector which can handle all CRUD requests to the API. In this example the APIConnector checks if there is a Json Web Token present and if there is, it sends the token with all requests (since on this example all requests excluding login and registering require authorization) the API then validates the token.
public class APIConnecter
{
HttpClient _httpClient;
private string _jwtToken;
public APIConnecter()
{
_httpClient = new HttpClient();
ISettings _appSettings;
_appSettings = _appSettings = CrossSettings.Current;
_jwtToken = Settings.JwtToken;
if(!String.IsNullOrEmpty(_jwtToken))
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", _jwtToken);
}
public async Task<HttpResponseMessage> GetRequest(Uri uri)
{
var response = await _httpClient.GetAsync(uri);
return response;
}
public async Task<HttpResponseMessage> DeleteRequest(Uri uri)
{
var response = await _httpClient.DeleteAsync(uri);
return response;
}
public async Task<HttpResponseMessage> PostRequest(Uri uri, HttpContent content)
{
var response = await _httpClient.PostAsync(uri, content);
return response;
}
public async Task<HttpResponseMessage> PutRequest(Uri uri, HttpContent content)
{
var response = await _httpClient.PutAsync(uri, content);
return response;
}
}
Your Login on your api would look something like this
public async Task<IActionResult> Login([FromBody] CredentialModel credentialModel)
{
var user = await _userManager.FindByEmailAsync(credentialModel.Email);
if (user == null)
return NotFound();
if (_hasher.VerifyHashedPassword(user, user.PasswordHash, credentialModel.Password) != PasswordVerificationResult.Success)
return Unauthorized();
var token = CreateToken(user);
if (token == null)
return StatusCode(500, "A problem happened while handling your request");
return Ok(new
{
token = new JwtSecurityTokenHandler().WriteToken(token),
experation = token.ValidTo
});
}