diff --git a/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/LoginController.cs b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/LoginController.cs new file mode 100644 index 0000000000..67de8fc9e8 --- /dev/null +++ b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/LoginController.cs @@ -0,0 +1,103 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Localization; +using Volo.Abp.Account.Web.Areas.Account.Controllers.Models; +using Volo.Abp.Account.Web.Localization; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Identity; +using UserLoginInfo = Volo.Abp.Account.Web.Areas.Account.Controllers.Models.UserLoginInfo; + +namespace Volo.Abp.Account.Web.Areas.Account.Controllers +{ + [RemoteService] + [Controller] + [ControllerName("Login")] + [Area("Account")] + [Route("api/account/login")] + public class LoginController : AbpController + { + private readonly SignInManager _signInManager; + public IStringLocalizer L { get; set; } + public string AspNetCoreIdentityCookieName = ".AspNetCore." + IdentityConstants.ApplicationScheme; + + public LoginController(SignInManager signInManager) + { + _signInManager = signInManager; + } + + [HttpPost] + [Route("")] + public virtual async Task Login(UserLoginInfo login) + { + if (login == null) + { + throw new ArgumentException(nameof(login)); + } + + if (login.UserNameOrEmailAddress.IsNullOrEmpty()) + { + throw new ArgumentNullException(nameof(login.UserNameOrEmailAddress)); + } + + if (login.Password.IsNullOrEmpty()) + { + throw new ArgumentNullException(nameof(login.Password)); + } + + var result = await _signInManager.PasswordSignInAsync( + login.UserNameOrEmailAddress, + login.Password, + login.RememberMe, + true + ); + + if (result.IsLockedOut) + { + return Json(new AbpLoginResult(LoginResultType.LockedOut)); + } + + if (result.RequiresTwoFactor) + { + return Json(new AbpLoginResult(LoginResultType.RequiresTwoFactor)); + } + + if (result.IsNotAllowed) + { + return Json(new AbpLoginResult(LoginResultType.NotAllowed)); + } + + if (!result.Succeeded) + { + return Json(new AbpLoginResult(LoginResultType.InvalidUserNameOrPassword)); + } + + return Json(new AbpLoginResult(LoginResultType.Success) + { + IdentityCookieToken = GetCookieValueFromResponse(AspNetCoreIdentityCookieName) //todo: cookie name can be retrieved from UseAuthentication options + }); + } + + private string GetCookieValueFromResponse(string cookieName) + { + foreach (var headers in Response.Headers.Values) + { + foreach (var header in headers) + { + if (!header.StartsWith($"{cookieName}=")) + { + continue; + } + + var p1 = header.IndexOf('='); + var p2 = header.IndexOf(';'); + return header.Substring(p1 + 1, p2 - p1 - 1); + } + } + + return null; + } + + } +} diff --git a/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/Models/AbpLoginResult.cs b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/Models/AbpLoginResult.cs new file mode 100644 index 0000000000..b47a7dc9ef --- /dev/null +++ b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/Models/AbpLoginResult.cs @@ -0,0 +1,18 @@ +using Volo.Abp.Account.Web.Areas.Account.Controllers.Models; + +namespace Volo.Abp.Account.Web.Areas.Account.Controllers +{ + public class AbpLoginResult + { + public AbpLoginResult(LoginResultType result) + { + Result = result; + } + + public string IdentityCookieToken { get; set; } + + public LoginResultType Result { get; } + + public string Description => Result.ToString(); + } +} \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/Models/LoginResultType.cs b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/Models/LoginResultType.cs new file mode 100644 index 0000000000..6e92802136 --- /dev/null +++ b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/Models/LoginResultType.cs @@ -0,0 +1,15 @@ +namespace Volo.Abp.Account.Web.Areas.Account.Controllers.Models +{ + public enum LoginResultType : byte + { + Success = 1, + + InvalidUserNameOrPassword = 2, + + NotAllowed = 3, + + LockedOut = 4, + + RequiresTwoFactor = 5 + } +} \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/Models/UserLoginInfo.cs b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/Models/UserLoginInfo.cs new file mode 100644 index 0000000000..a856157bc4 --- /dev/null +++ b/modules/account/src/Volo.Abp.Account.Web/Areas/Account/Controllers/Models/UserLoginInfo.cs @@ -0,0 +1,18 @@ +using System.ComponentModel.DataAnnotations; + +namespace Volo.Abp.Account.Web.Areas.Account.Controllers.Models +{ + public class UserLoginInfo + { + [Required] + [StringLength(255)] + public string UserNameOrEmailAddress { get; set; } + + [Required] + [StringLength(32)] + [DataType(DataType.Password)] + public string Password { get; set; } + + public bool RememberMe { get; set; } + } +} \ No newline at end of file