From db221d03c2d27dfcd1c38799ae8482b080c9ec8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 11 Oct 2017 11:43:43 +0300 Subject: [PATCH] Created simple login/logout/register for account module. --- Volo.Abp.sln | 16 ++++- .../AbpDesk.Web.Mvc/AbpDeskWebMvcModule.cs | 5 ++ ...o.Abp.Account.Application.Contracts.csproj | 20 +++++++ .../AbpAccountApplicationContractsModule.cs | 13 ++++ .../Volo/Abp/Account/ILoginAppService.cs | 8 +++ .../Volo.Abp.Account.Application.csproj | 20 +++++++ .../AbpAccountApplicationContractsModule.cs | 14 +++++ .../Volo/Abp/Account/LoginAppService.cs | 6 ++ .../AbpAccountWebModule.cs | 3 + .../Controllers/AccountControllerBase.cs | 58 ++++++++++++++++++ .../Account/Controllers/LoginController.cs | 41 ++++++++++++- .../Account/Controllers/LogoutController.cs | 28 +++++++++ .../Account/Controllers/RegisterController.cs | 52 ++++++++++++++++ .../Areas/Account/Models/Login/LoginModel.cs | 17 ++++++ .../Account/Models/Register/RegisterModel.cs | 20 +++++++ .../Areas/Account/Views/Login/Index.cshtml | 14 +++-- .../Areas/Account/Views/Register/Index.cshtml | 19 ++++++ .../Volo.Abp.Account.Web.csproj | 3 +- .../Shared/Components/AbpMenu/Default.cshtml | 11 ++-- .../Abp/Identity/IdentityUserAppService.cs | 3 +- .../AbpIdentityServiceCollectionExtensions.cs | 44 ++++++++++++++ .../Abp/Identity/AbpIdentityDomainModule.cs | 2 +- .../Volo/Abp/Identity/IdentityRoleStore.cs | 19 +++--- .../Volo/Abp/Identity/IdentityUserStore.cs | 60 ++++++++++--------- .../Identity/Controllers/UsersController.cs | 2 + 25 files changed, 446 insertions(+), 52 deletions(-) create mode 100644 src/Volo.Abp.Account.Application.Contracts/Volo.Abp.Account.Application.Contracts.csproj create mode 100644 src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/AbpAccountApplicationContractsModule.cs create mode 100644 src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/ILoginAppService.cs create mode 100644 src/Volo.Abp.Account.Application/Volo.Abp.Account.Application.csproj create mode 100644 src/Volo.Abp.Account.Application/Volo/Abp/Account/AbpAccountApplicationContractsModule.cs create mode 100644 src/Volo.Abp.Account.Application/Volo/Abp/Account/LoginAppService.cs create mode 100644 src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountControllerBase.cs create mode 100644 src/Volo.Abp.Account.Web/Areas/Account/Controllers/LogoutController.cs create mode 100644 src/Volo.Abp.Account.Web/Areas/Account/Controllers/RegisterController.cs create mode 100644 src/Volo.Abp.Account.Web/Areas/Account/Models/Login/LoginModel.cs create mode 100644 src/Volo.Abp.Account.Web/Areas/Account/Models/Register/RegisterModel.cs create mode 100644 src/Volo.Abp.Account.Web/Areas/Account/Views/Register/Index.cshtml create mode 100644 src/Volo.Abp.Identity.Domain/Microsoft/Extensions/DependencyInjection/AbpIdentityServiceCollectionExtensions.cs diff --git a/Volo.Abp.sln b/Volo.Abp.sln index 3b992ae465..4f5e933152 100644 --- a/Volo.Abp.sln +++ b/Volo.Abp.sln @@ -148,7 +148,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.Ver EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Abp.Account", "Abp.Account", "{DB012309-74FD-4D5A-B843-DD77BF053BF4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Account.Web", "src\Volo.Abp.Account.Web\Volo.Abp.Account.Web.csproj", "{F7DDF25E-58B1-4F68-AEDA-4F2FB4F4467B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Account.Web", "src\Volo.Abp.Account.Web\Volo.Abp.Account.Web.csproj", "{F7DDF25E-58B1-4F68-AEDA-4F2FB4F4467B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Account.Application", "src\Volo.Abp.Account.Application\Volo.Abp.Account.Application.csproj", "{723709F9-09FB-4715-A5D2-DAC8833D8CF7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Account.Application.Contracts", "src\Volo.Abp.Account.Application.Contracts\Volo.Abp.Account.Application.Contracts.csproj", "{3E62ED84-8792-4DA6-9B0A-AADEA183C2B3}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -380,6 +384,14 @@ Global {F7DDF25E-58B1-4F68-AEDA-4F2FB4F4467B}.Debug|Any CPU.Build.0 = Debug|Any CPU {F7DDF25E-58B1-4F68-AEDA-4F2FB4F4467B}.Release|Any CPU.ActiveCfg = Release|Any CPU {F7DDF25E-58B1-4F68-AEDA-4F2FB4F4467B}.Release|Any CPU.Build.0 = Release|Any CPU + {723709F9-09FB-4715-A5D2-DAC8833D8CF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {723709F9-09FB-4715-A5D2-DAC8833D8CF7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {723709F9-09FB-4715-A5D2-DAC8833D8CF7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {723709F9-09FB-4715-A5D2-DAC8833D8CF7}.Release|Any CPU.Build.0 = Release|Any CPU + {3E62ED84-8792-4DA6-9B0A-AADEA183C2B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3E62ED84-8792-4DA6-9B0A-AADEA183C2B3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3E62ED84-8792-4DA6-9B0A-AADEA183C2B3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3E62ED84-8792-4DA6-9B0A-AADEA183C2B3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -451,6 +463,8 @@ Global {A8C8B76D-0869-4C11-AC55-DB9DD115788E} = {37087D1B-3693-4E96-983D-A69F210BDE53} {DB012309-74FD-4D5A-B843-DD77BF053BF4} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {F7DDF25E-58B1-4F68-AEDA-4F2FB4F4467B} = {DB012309-74FD-4D5A-B843-DD77BF053BF4} + {723709F9-09FB-4715-A5D2-DAC8833D8CF7} = {DB012309-74FD-4D5A-B843-DD77BF053BF4} + {3E62ED84-8792-4DA6-9B0A-AADEA183C2B3} = {DB012309-74FD-4D5A-B843-DD77BF053BF4} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/src/AbpDesk/AbpDesk.Web.Mvc/AbpDeskWebMvcModule.cs b/src/AbpDesk/AbpDesk.Web.Mvc/AbpDeskWebMvcModule.cs index 0250c8e4c6..aa790692fb 100644 --- a/src/AbpDesk/AbpDesk.Web.Mvc/AbpDeskWebMvcModule.cs +++ b/src/AbpDesk/AbpDesk.Web.Mvc/AbpDeskWebMvcModule.cs @@ -3,8 +3,11 @@ using AbpDesk.EntityFrameworkCore; using AbpDesk.Web.Mvc.Navigation; using AbpDesk.Web.Mvc.Temp; using Autofac; +using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Volo.Abp; @@ -82,6 +85,8 @@ namespace AbpDesk.Web.Mvc app.UseStaticFiles(); app.UseEmbeddedFiles(); + app.UseAuthentication(); + app.UseMvc(routes => { routes.MapRoute( diff --git a/src/Volo.Abp.Account.Application.Contracts/Volo.Abp.Account.Application.Contracts.csproj b/src/Volo.Abp.Account.Application.Contracts/Volo.Abp.Account.Application.Contracts.csproj new file mode 100644 index 0000000000..f56ec40843 --- /dev/null +++ b/src/Volo.Abp.Account.Application.Contracts/Volo.Abp.Account.Application.Contracts.csproj @@ -0,0 +1,20 @@ + + + + + + netstandard2.0 + Volo.Abp.Account.Application.Contracts + Volo.Abp.Account.Application.Contracts + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + + + + + + + + diff --git a/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/AbpAccountApplicationContractsModule.cs b/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/AbpAccountApplicationContractsModule.cs new file mode 100644 index 0000000000..7c57bb8c50 --- /dev/null +++ b/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/AbpAccountApplicationContractsModule.cs @@ -0,0 +1,13 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Modularity; + +namespace Volo.Abp.Account +{ + public class AbpAccountApplicationContractsModule : AbpModule + { + public override void ConfigureServices(IServiceCollection services) + { + services.AddAssemblyOf(); + } + } +} diff --git a/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/ILoginAppService.cs b/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/ILoginAppService.cs new file mode 100644 index 0000000000..1bd1be4a17 --- /dev/null +++ b/src/Volo.Abp.Account.Application.Contracts/Volo/Abp/Account/ILoginAppService.cs @@ -0,0 +1,8 @@ +using Volo.Abp.Application.Services; + +namespace Volo.Abp.Account +{ + public interface ILoginAppService : IApplicationService + { + } +} diff --git a/src/Volo.Abp.Account.Application/Volo.Abp.Account.Application.csproj b/src/Volo.Abp.Account.Application/Volo.Abp.Account.Application.csproj new file mode 100644 index 0000000000..bc878d5ec8 --- /dev/null +++ b/src/Volo.Abp.Account.Application/Volo.Abp.Account.Application.csproj @@ -0,0 +1,20 @@ + + + + + + netstandard2.0 + Volo.Abp.Account.Application + Volo.Abp.Account.Application + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + + + + + + + + diff --git a/src/Volo.Abp.Account.Application/Volo/Abp/Account/AbpAccountApplicationContractsModule.cs b/src/Volo.Abp.Account.Application/Volo/Abp/Account/AbpAccountApplicationContractsModule.cs new file mode 100644 index 0000000000..9b86e5b95f --- /dev/null +++ b/src/Volo.Abp.Account.Application/Volo/Abp/Account/AbpAccountApplicationContractsModule.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Modularity; + +namespace Volo.Abp.Account +{ + [DependsOn(typeof(AbpAccountApplicationContractsModule))] + public class AbpAccountApplicationModule : AbpModule + { + public override void ConfigureServices(IServiceCollection services) + { + services.AddAssemblyOf(); + } + } +} diff --git a/src/Volo.Abp.Account.Application/Volo/Abp/Account/LoginAppService.cs b/src/Volo.Abp.Account.Application/Volo/Abp/Account/LoginAppService.cs new file mode 100644 index 0000000000..6aa9f57d01 --- /dev/null +++ b/src/Volo.Abp.Account.Application/Volo/Abp/Account/LoginAppService.cs @@ -0,0 +1,6 @@ +namespace Volo.Abp.Account +{ + public class LoginAppService : ILoginAppService + { + } +} diff --git a/src/Volo.Abp.Account.Web/AbpAccountWebModule.cs b/src/Volo.Abp.Account.Web/AbpAccountWebModule.cs index 4645d76dab..39bed90383 100644 --- a/src/Volo.Abp.Account.Web/AbpAccountWebModule.cs +++ b/src/Volo.Abp.Account.Web/AbpAccountWebModule.cs @@ -2,11 +2,14 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap; using Volo.Abp.EmbeddedFiles; +using Volo.Abp.Identity; using Volo.Abp.Modularity; namespace Volo.Abp.Account.Web { + [DependsOn(typeof(AbpIdentityDomainModule))] [DependsOn(typeof(AbpAspNetCoreMvcUiBootstrapModule))] + [DependsOn(typeof(AbpAccountApplicationContractsModule))] public class AbpAccountWebModule : AbpModule { public override void ConfigureServices(IServiceCollection services) diff --git a/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountControllerBase.cs b/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountControllerBase.cs new file mode 100644 index 0000000000..9b720ab123 --- /dev/null +++ b/src/Volo.Abp.Account.Web/Areas/Account/Controllers/AccountControllerBase.cs @@ -0,0 +1,58 @@ +using System; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Ui; + +namespace Volo.Abp.Account.Web.Areas.Account.Controllers +{ + public abstract class AccountControllerBase : AbpController + { + protected RedirectResult RedirectSafely(string returnUrl, string returnUrlHash = null) + { + return Redirect(GetRedirectUrl(returnUrl, returnUrlHash)); + } + + protected void CheckIdentityErrors(IdentityResult identityResult) + { + if (!identityResult.Succeeded) + { + throw new UserFriendlyException("Operation failed!"); + } + + //identityResult.CheckErrors(LocalizationManager); //TODO: Get from old Abp + } + + private string GetRedirectUrl(string returnUrl, string returnUrlHash = null) + { + returnUrl = NormalizeReturnUrl(returnUrl); + + if (!returnUrlHash.IsNullOrWhiteSpace()) + { + returnUrl = returnUrl + returnUrlHash; + } + + return returnUrl; + } + + private string NormalizeReturnUrl(string returnUrl) + { + if (returnUrl.IsNullOrEmpty()) + { + return GetAppHomeUrl(); + } + + if (Url.IsLocalUrl(returnUrl)) + { + return returnUrl; + } + + return GetAppHomeUrl(); + } + + private string GetAppHomeUrl() + { + return "/"; //TODO: ??? + } + } +} diff --git a/src/Volo.Abp.Account.Web/Areas/Account/Controllers/LoginController.cs b/src/Volo.Abp.Account.Web/Areas/Account/Controllers/LoginController.cs index 178ee4883e..affdbca2c5 100644 --- a/src/Volo.Abp.Account.Web/Areas/Account/Controllers/LoginController.cs +++ b/src/Volo.Abp.Account.Web/Areas/Account/Controllers/LoginController.cs @@ -1,14 +1,49 @@ -using Microsoft.AspNetCore.Mvc; -using Volo.Abp.AspNetCore.Mvc; +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.Account.Web.Areas.Account.Models.Login; +using Volo.Abp.Identity; +using Volo.Abp.Ui; namespace Volo.Abp.Account.Web.Areas.Account.Controllers { [Area("Account")] - public class LoginController : AbpController + public class LoginController : AccountControllerBase { + private readonly SignInManager _signInManager; + + public LoginController(SignInManager signInManager) + { + _signInManager = signInManager; + } + public IActionResult Index() { return View(); } + + [HttpPost] + public async Task Index(LoginModel loginModel, string returnUrl = "", string returnUrlHash = "") + { + if (!ModelState.IsValid) + { + throw new NotImplementedException(); + } + + var result = await _signInManager.PasswordSignInAsync( + loginModel.UserNameOrEmailAddress, + loginModel.Password, + loginModel.RememberMe, + true + ); + + if (!result.Succeeded) + { + throw new UserFriendlyException("Login failed!"); //TODO: Handle other cases, do not throw exception + } + + return RedirectSafely(returnUrl, returnUrlHash); + } } } diff --git a/src/Volo.Abp.Account.Web/Areas/Account/Controllers/LogoutController.cs b/src/Volo.Abp.Account.Web/Areas/Account/Controllers/LogoutController.cs new file mode 100644 index 0000000000..a315286f27 --- /dev/null +++ b/src/Volo.Abp.Account.Web/Areas/Account/Controllers/LogoutController.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.Identity; + +namespace Volo.Abp.Account.Web.Areas.Account.Controllers +{ + [Area("Account")] + public class LogoutController : AccountControllerBase + { + private readonly SignInManager _signInManager; + + public LogoutController(SignInManager signInManager) + { + _signInManager = signInManager; + } + + public async Task Index() + { + await _signInManager.SignOutAsync(); + + return RedirectToAction("Index", "Login"); + } + } +} diff --git a/src/Volo.Abp.Account.Web/Areas/Account/Controllers/RegisterController.cs b/src/Volo.Abp.Account.Web/Areas/Account/Controllers/RegisterController.cs new file mode 100644 index 0000000000..01328dd173 --- /dev/null +++ b/src/Volo.Abp.Account.Web/Areas/Account/Controllers/RegisterController.cs @@ -0,0 +1,52 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.Account.Web.Areas.Account.Models.Register; +using Volo.Abp.Identity; + +namespace Volo.Abp.Account.Web.Areas.Account.Controllers +{ + [Area("Account")] + public class RegisterController : AccountControllerBase + { + private readonly IdentityUserManager _userManager; + private readonly SignInManager _signInManager; + + public RegisterController(IdentityUserManager userManager, SignInManager signInManager) + { + _userManager = userManager; + _signInManager = signInManager; + } + + public IActionResult Index() + { + return View(); + } + + [HttpPost] + //TODO: [ValidateAntiForgeryToken] + public async Task Index(RegisterModel registerModel, string returnUrl = "", string returnUrlHash = "") + { + if (!ModelState.IsValid) + { + throw new NotImplementedException(); + } + + var user = new IdentityUser(GuidGenerator.Create(), registerModel.UserName); + + var result = await _userManager.CreateAsync(user, registerModel.Password); + + if (!result.Succeeded) + { + throw new NotImplementedException(); + } + + await _userManager.SetEmailAsync(user, registerModel.EmailAddress); + + await _signInManager.SignInAsync(user, isPersistent: false); + + return RedirectSafely(returnUrl, returnUrlHash); + } + } +} diff --git a/src/Volo.Abp.Account.Web/Areas/Account/Models/Login/LoginModel.cs b/src/Volo.Abp.Account.Web/Areas/Account/Models/Login/LoginModel.cs new file mode 100644 index 0000000000..a72c3e6f32 --- /dev/null +++ b/src/Volo.Abp.Account.Web/Areas/Account/Models/Login/LoginModel.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; + +namespace Volo.Abp.Account.Web.Areas.Account.Models.Login +{ + public class LoginModel + { + [Required] + [MaxLength(255)] + public string UserNameOrEmailAddress { get; set; } + + [Required] + [MaxLength(32)] + public string Password { get; set; } + + public bool RememberMe { get; set; } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Account.Web/Areas/Account/Models/Register/RegisterModel.cs b/src/Volo.Abp.Account.Web/Areas/Account/Models/Register/RegisterModel.cs new file mode 100644 index 0000000000..6990c80cbf --- /dev/null +++ b/src/Volo.Abp.Account.Web/Areas/Account/Models/Register/RegisterModel.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; + +namespace Volo.Abp.Account.Web.Areas.Account.Models.Register +{ + public class RegisterModel + { + [Required] + [MaxLength(32)] + public string UserName { get; set; } + + [Required] + [EmailAddress] + [MaxLength(255)] + public string EmailAddress { get; set; } + + [Required] + [MaxLength(32)] + public string Password { get; set; } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Account.Web/Areas/Account/Views/Login/Index.cshtml b/src/Volo.Abp.Account.Web/Areas/Account/Views/Login/Index.cshtml index 395fc6568d..155af50a68 100644 --- a/src/Volo.Abp.Account.Web/Areas/Account/Views/Login/Index.cshtml +++ b/src/Volo.Abp.Account.Web/Areas/Account/Views/Login/Index.cshtml @@ -1,21 +1,25 @@ 
-
-
+
+
- +
- +
+ +
+ Register +
\ No newline at end of file diff --git a/src/Volo.Abp.Account.Web/Areas/Account/Views/Register/Index.cshtml b/src/Volo.Abp.Account.Web/Areas/Account/Views/Register/Index.cshtml new file mode 100644 index 0000000000..f0d62fbdf4 --- /dev/null +++ b/src/Volo.Abp.Account.Web/Areas/Account/Views/Register/Index.cshtml @@ -0,0 +1,19 @@ +
+
+
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
\ No newline at end of file diff --git a/src/Volo.Abp.Account.Web/Volo.Abp.Account.Web.csproj b/src/Volo.Abp.Account.Web/Volo.Abp.Account.Web.csproj index b0fded09f3..cff7fb67a5 100644 --- a/src/Volo.Abp.Account.Web/Volo.Abp.Account.Web.csproj +++ b/src/Volo.Abp.Account.Web/Volo.Abp.Account.Web.csproj @@ -18,8 +18,9 @@ + - + diff --git a/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/Views/Shared/Components/AbpMenu/Default.cshtml b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/Views/Shared/Components/AbpMenu/Default.cshtml index f00fcfe765..4a2365b898 100644 --- a/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/Views/Shared/Components/AbpMenu/Default.cshtml +++ b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/Views/Shared/Components/AbpMenu/Default.cshtml @@ -32,9 +32,12 @@ } } -
- - -
+ + @if (Context.User?.Identity?.IsAuthenticated == true) + { +
+ Logout /* TODO: ?? */ +
+ }
diff --git a/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs b/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs index fc264b4a60..4fdd77c26e 100644 --- a/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs +++ b/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs @@ -42,8 +42,7 @@ namespace Volo.Abp.Identity var user = new IdentityUser(GuidGenerator.Create(), input.UserName); await UpdateUserByInput(user, input); - await _userManager.AddPasswordAsync(user, input.Password); - await _userManager.CreateAsync(user); + await _userManager.CreateAsync(user, input.Password); await CurrentUnitOfWork.SaveChangesAsync(); return ObjectMapper.Map(user); diff --git a/src/Volo.Abp.Identity.Domain/Microsoft/Extensions/DependencyInjection/AbpIdentityServiceCollectionExtensions.cs b/src/Volo.Abp.Identity.Domain/Microsoft/Extensions/DependencyInjection/AbpIdentityServiceCollectionExtensions.cs new file mode 100644 index 0000000000..62d94450e8 --- /dev/null +++ b/src/Volo.Abp.Identity.Domain/Microsoft/Extensions/DependencyInjection/AbpIdentityServiceCollectionExtensions.cs @@ -0,0 +1,44 @@ +using System; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Volo.Abp.Identity; + +namespace Microsoft.Extensions.DependencyInjection +{ + //TODO: AspNetUserManager overrides CancellationToken so we can make same functionality available! + + public static class AbpIdentityServiceCollectionExtensions + { + public static IdentityBuilder AddAbpIdentity(this IServiceCollection services) + { + return services.AddAbpIdentity(setupAction: null); + } + + public static IdentityBuilder AddAbpIdentity(this IServiceCollection services, Action setupAction) + { + //AbpRoleManager + services.TryAddScoped(); + services.TryAddScoped(typeof(RoleManager), provider => provider.GetService(typeof(IdentityRoleManager))); + + //AbpUserManager + services.TryAddScoped(); + services.TryAddScoped(typeof(UserManager), provider => provider.GetService(typeof(IdentityUserManager))); + + //AbpSecurityStampValidator TODO: We may need to add this in order to ValidateAsync principal! + //services.TryAddScoped>(); + //services.TryAddScoped(typeof(SecurityStampValidator), provider => provider.GetService(typeof(AbpSecurityStampValidator))); + //services.TryAddScoped(typeof(ISecurityStampValidator), provider => provider.GetService(typeof(AbpSecurityStampValidator))); + + //AbpUserStore + services.TryAddScoped(); + services.TryAddScoped(typeof(IUserStore), provider => provider.GetService(typeof(IdentityUserStore))); + + //AbpRoleStore + services.TryAddScoped(); + services.TryAddScoped(typeof(IRoleStore), provider => provider.GetService(typeof(IdentityRoleStore))); + + return services.AddIdentity(setupAction); + //return services.AddIdentityCore(setupAction); + } + } +} diff --git a/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs b/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs index 150a8a7411..2b2ce8be16 100644 --- a/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs +++ b/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs @@ -9,7 +9,7 @@ namespace Volo.Abp.Identity public override void ConfigureServices(IServiceCollection services) { //TODO: How to configure options of AddIdentity (and return value) - services.AddIdentity(); + services.AddAbpIdentity(); services.AddAssemblyOf(); } } diff --git a/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleStore.cs b/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleStore.cs index c96451594d..1acce6aca8 100644 --- a/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleStore.cs +++ b/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityRoleStore.cs @@ -8,6 +8,7 @@ using JetBrains.Annotations; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Logging; using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Repositories; using Volo.Abp.Guids; using Volo.Abp.Uow; @@ -262,13 +263,15 @@ namespace Volo.Abp.Identity /// The role whose claims should be retrieved. /// The used to propagate notifications that the operation should be canceled. /// A that contains the claims granted to a role. - public Task> GetClaimsAsync([NotNull] IdentityRole role, CancellationToken cancellationToken = default(CancellationToken)) + public async Task> GetClaimsAsync([NotNull] IdentityRole role, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); Check.NotNull(role, nameof(role)); - return Task.FromResult>(role.Claims.Select(c => c.ToClaim()).ToList()); + await _roleRepository.EnsureCollectionLoadedAsync(role, r => r.Claims, cancellationToken); + + return role.Claims.Select(c => c.ToClaim()).ToList(); } /// @@ -278,16 +281,16 @@ namespace Volo.Abp.Identity /// The claim to add to the role. /// The used to propagate notifications that the operation should be canceled. /// The that represents the asynchronous operation. - public Task AddClaimAsync([NotNull] IdentityRole role, [NotNull] Claim claim, CancellationToken cancellationToken = default(CancellationToken)) + public async Task AddClaimAsync([NotNull] IdentityRole role, [NotNull] Claim claim, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); Check.NotNull(role, nameof(role)); Check.NotNull(claim, nameof(claim)); - role.AddClaim(_guidGenerator, claim); + await _roleRepository.EnsureCollectionLoadedAsync(role, r => r.Claims, cancellationToken); - return Task.FromResult(false); + role.AddClaim(_guidGenerator, claim); } /// @@ -297,14 +300,14 @@ namespace Volo.Abp.Identity /// The claim to remove from the role. /// The used to propagate notifications that the operation should be canceled. /// The that represents the asynchronous operation. - public Task RemoveClaimAsync([NotNull] IdentityRole role, [NotNull] Claim claim, CancellationToken cancellationToken = default(CancellationToken)) + public async Task RemoveClaimAsync([NotNull] IdentityRole role, [NotNull] Claim claim, CancellationToken cancellationToken = default(CancellationToken)) { Check.NotNull(role, nameof(role)); Check.NotNull(claim, nameof(claim)); - role.RemoveClaim(claim); + await _roleRepository.EnsureCollectionLoadedAsync(role, r => r.Claims, cancellationToken); - return Task.CompletedTask; + role.RemoveClaim(claim); } } } diff --git a/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs b/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs index 2cc48a9c3f..201d757e28 100644 --- a/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs +++ b/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserStore.cs @@ -418,13 +418,15 @@ namespace Volo.Abp.Identity /// The user whose claims should be retrieved. /// The used to propagate notifications that the operation should be canceled. /// A that contains the claims granted to a user. - public virtual Task> GetClaimsAsync([NotNull] IdentityUser user, CancellationToken cancellationToken = default(CancellationToken)) + public virtual async Task> GetClaimsAsync([NotNull] IdentityUser user, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); Check.NotNull(user, nameof(user)); - return Task.FromResult>(user.Claims.Select(c => c.ToClaim()).ToList()); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Claims, cancellationToken); + + return user.Claims.Select(c => c.ToClaim()).ToList(); } /// @@ -434,16 +436,16 @@ namespace Volo.Abp.Identity /// The claim to add to the user. /// The used to propagate notifications that the operation should be canceled. /// The that represents the asynchronous operation. - public virtual Task AddClaimsAsync([NotNull] IdentityUser user, [NotNull] IEnumerable claims, CancellationToken cancellationToken = default(CancellationToken)) + public virtual async Task AddClaimsAsync([NotNull] IdentityUser user, [NotNull] IEnumerable claims, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); Check.NotNull(user, nameof(user)); Check.NotNull(claims, nameof(claims)); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Claims, cancellationToken); + user.AddClaims(_guidGenerator, claims); - - return Task.CompletedTask; } /// @@ -454,7 +456,7 @@ namespace Volo.Abp.Identity /// The new claim replacing the . /// The used to propagate notifications that the operation should be canceled. /// The that represents the asynchronous operation. - public virtual Task ReplaceClaimAsync([NotNull] IdentityUser user, [NotNull] Claim claim, [NotNull] Claim newClaim, CancellationToken cancellationToken = default(CancellationToken)) + public virtual async Task ReplaceClaimAsync([NotNull] IdentityUser user, [NotNull] Claim claim, [NotNull] Claim newClaim, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); @@ -462,9 +464,9 @@ namespace Volo.Abp.Identity Check.NotNull(claim, nameof(claim)); Check.NotNull(newClaim, nameof(newClaim)); - user.ReplaceClaim(claim, newClaim); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Claims, cancellationToken); - return Task.CompletedTask; + user.ReplaceClaim(claim, newClaim); } /// @@ -474,16 +476,16 @@ namespace Volo.Abp.Identity /// The claim to remove. /// The used to propagate notifications that the operation should be canceled. /// The that represents the asynchronous operation. - public virtual Task RemoveClaimsAsync([NotNull] IdentityUser user, [NotNull] IEnumerable claims, CancellationToken cancellationToken = default(CancellationToken)) + public virtual async Task RemoveClaimsAsync([NotNull] IdentityUser user, [NotNull] IEnumerable claims, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); Check.NotNull(user, nameof(user)); Check.NotNull(claims, nameof(claims)); - user.RemoveClaims(claims); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Claims, cancellationToken); - return Task.CompletedTask; + user.RemoveClaims(claims); } /// @@ -493,16 +495,16 @@ namespace Volo.Abp.Identity /// The login to add to the user. /// The used to propagate notifications that the operation should be canceled. /// The that represents the asynchronous operation. - public virtual Task AddLoginAsync([NotNull] IdentityUser user, [NotNull] UserLoginInfo login, CancellationToken cancellationToken = default(CancellationToken)) + public virtual async Task AddLoginAsync([NotNull] IdentityUser user, [NotNull] UserLoginInfo login, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); Check.NotNull(user, nameof(user)); Check.NotNull(login, nameof(login)); - user.AddLogin(_guidGenerator, login); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Logins, cancellationToken); - return Task.CompletedTask; + user.AddLogin(_guidGenerator, login); } /// @@ -513,7 +515,7 @@ namespace Volo.Abp.Identity /// The key provided by the to identify a user. /// The used to propagate notifications that the operation should be canceled. /// The that represents the asynchronous operation. - public virtual Task RemoveLoginAsync([NotNull] IdentityUser user, [NotNull] string loginProvider, [NotNull] string providerKey, CancellationToken cancellationToken = default(CancellationToken)) + public virtual async Task RemoveLoginAsync([NotNull] IdentityUser user, [NotNull] string loginProvider, [NotNull] string providerKey, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); @@ -521,9 +523,9 @@ namespace Volo.Abp.Identity Check.NotNull(loginProvider, nameof(loginProvider)); Check.NotNull(providerKey, nameof(providerKey)); - user.RemoveLogin(loginProvider, providerKey); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Logins, cancellationToken); - return Task.CompletedTask; + user.RemoveLogin(loginProvider, providerKey); } /// @@ -534,13 +536,15 @@ namespace Volo.Abp.Identity /// /// The for the asynchronous operation, containing a list of for the specified , if any. /// - public virtual Task> GetLoginsAsync([NotNull] IdentityUser user, CancellationToken cancellationToken = default(CancellationToken)) + public virtual async Task> GetLoginsAsync([NotNull] IdentityUser user, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); Check.NotNull(user, nameof(user)); - return Task.FromResult>(user.Logins.Select(l => l.ToUserLoginInfo()).ToList()); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Logins, cancellationToken); + + return user.Logins.Select(l => l.ToUserLoginInfo()).ToList(); } /// @@ -990,15 +994,15 @@ namespace Volo.Abp.Identity /// The value of the token. /// The used to propagate notifications that the operation should be canceled. /// The that represents the asynchronous operation. - public virtual Task SetTokenAsync([NotNull] IdentityUser user, string loginProvider, string name, string value, CancellationToken cancellationToken) + public virtual async Task SetTokenAsync([NotNull] IdentityUser user, string loginProvider, string name, string value, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); Check.NotNull(user, nameof(user)); - user.SetToken(_guidGenerator, loginProvider, name, value); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Tokens, cancellationToken); - return Task.CompletedTask; + user.SetToken(_guidGenerator, loginProvider, name, value); } /// @@ -1009,15 +1013,15 @@ namespace Volo.Abp.Identity /// The name of the token. /// The used to propagate notifications that the operation should be canceled. /// The that represents the asynchronous operation. - public Task RemoveTokenAsync(IdentityUser user, string loginProvider, string name, CancellationToken cancellationToken) + public async Task RemoveTokenAsync(IdentityUser user, string loginProvider, string name, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); Check.NotNull(user, nameof(user)); - user.RemoveToken(loginProvider, name); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Tokens, cancellationToken); - return Task.CompletedTask; + user.RemoveToken(loginProvider, name); } /// @@ -1028,13 +1032,15 @@ namespace Volo.Abp.Identity /// The name of the token. /// The used to propagate notifications that the operation should be canceled. /// The that represents the asynchronous operation. - public Task GetTokenAsync(IdentityUser user, string loginProvider, string name, CancellationToken cancellationToken) + public async Task GetTokenAsync(IdentityUser user, string loginProvider, string name, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); Check.NotNull(user, nameof(user)); - return Task.FromResult(user.FindToken(loginProvider, name)?.Value); + await _userRepository.EnsureCollectionLoadedAsync(user, u => u.Tokens, cancellationToken); + + return user.FindToken(loginProvider, name)?.Value; } public void Dispose() diff --git a/src/Volo.Abp.Identity.Web/Areas/Identity/Controllers/UsersController.cs b/src/Volo.Abp.Identity.Web/Areas/Identity/Controllers/UsersController.cs index 9450115d66..cb43d9833e 100644 --- a/src/Volo.Abp.Identity.Web/Areas/Identity/Controllers/UsersController.cs +++ b/src/Volo.Abp.Identity.Web/Areas/Identity/Controllers/UsersController.cs @@ -1,4 +1,5 @@ using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Volo.Abp.Application.Dtos; using Volo.Abp.AspNetCore.Mvc; @@ -6,6 +7,7 @@ using Volo.Abp.AspNetCore.Mvc; namespace Volo.Abp.Identity.Web.Areas.Identity.Controllers { [Area("Identity")] + [Authorize] public class UsersController : AbpController { private readonly IIdentityUserAppService _userAppService;