diff --git a/Volo.Abp.sln b/Volo.Abp.sln index 6cbfed4ab1..4f5e933152 100644 --- a/Volo.Abp.sln +++ b/Volo.Abp.sln @@ -144,7 +144,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleConsoleDemo", "test\S EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.EntityFrameworkCore.Tests.SecondContext", "test\Volo.Abp.EntityFrameworkCore.Tests.SecondContext\Volo.Abp.EntityFrameworkCore.Tests.SecondContext.csproj", "{127FC2BF-DC40-4370-B845-16088328264C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.AspNetCore.Mvc.Versioning.Tests", "test\Volo.Abp.AspNetCore.Mvc.Versioning.Tests\Volo.Abp.AspNetCore.Mvc.Versioning.Tests.csproj", "{A8C8B76D-0869-4C11-AC55-DB9DD115788E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.AspNetCore.Mvc.Versioning.Tests", "test\Volo.Abp.AspNetCore.Mvc.Versioning.Tests\Volo.Abp.AspNetCore.Mvc.Versioning.Tests.csproj", "{A8C8B76D-0869-4C11-AC55-DB9DD115788E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Abp.Account", "Abp.Account", "{DB012309-74FD-4D5A-B843-DD77BF053BF4}" +EndProject +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 @@ -372,6 +380,18 @@ Global {A8C8B76D-0869-4C11-AC55-DB9DD115788E}.Debug|Any CPU.Build.0 = Debug|Any CPU {A8C8B76D-0869-4C11-AC55-DB9DD115788E}.Release|Any CPU.ActiveCfg = Release|Any CPU {A8C8B76D-0869-4C11-AC55-DB9DD115788E}.Release|Any CPU.Build.0 = Release|Any CPU + {F7DDF25E-58B1-4F68-AEDA-4F2FB4F4467B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {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 @@ -441,6 +461,10 @@ Global {2B48CF90-DBDB-469F-941C-5B5AECEEACE0} = {37087D1B-3693-4E96-983D-A69F210BDE53} {127FC2BF-DC40-4370-B845-16088328264C} = {37087D1B-3693-4E96-983D-A69F210BDE53} {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/AbpDesk.Web.Mvc.csproj b/src/AbpDesk/AbpDesk.Web.Mvc/AbpDesk.Web.Mvc.csproj index 50640e7e03..0b36692389 100644 --- a/src/AbpDesk/AbpDesk.Web.Mvc/AbpDesk.Web.Mvc.csproj +++ b/src/AbpDesk/AbpDesk.Web.Mvc/AbpDesk.Web.Mvc.csproj @@ -20,6 +20,7 @@ + diff --git a/src/AbpDesk/AbpDesk.Web.Mvc/AbpDeskWebMvcModule.cs b/src/AbpDesk/AbpDesk.Web.Mvc/AbpDeskWebMvcModule.cs index c1c2ad2b36..aa790692fb 100644 --- a/src/AbpDesk/AbpDesk.Web.Mvc/AbpDeskWebMvcModule.cs +++ b/src/AbpDesk/AbpDesk.Web.Mvc/AbpDeskWebMvcModule.cs @@ -3,11 +3,15 @@ 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; +using Volo.Abp.Account.Web; using Volo.Abp.AspNetCore.EmbeddedFiles; using Volo.Abp.AspNetCore.Modularity; using Volo.Abp.AspNetCore.Mvc; @@ -24,12 +28,13 @@ namespace AbpDesk.Web.Mvc { [DependsOn( typeof(AbpAspNetCoreEmbeddedFilesModule), - typeof(AbpAspNetCoreMvcUiBootstrapModule), - typeof(AbpDeskApplicationModule), + typeof(AbpAspNetCoreMvcUiBootstrapModule), + typeof(AbpDeskApplicationModule), typeof(AbpDeskEntityFrameworkCoreModule), typeof(AbpIdentityHttpApiModule), typeof(AbpIdentityEntityFrameworkCoreModule), typeof(AbpIdentityWebModule), + typeof(AbpAccountWebModule), typeof(AbpAutofacModule) )] public class AbpDeskWebMvcModule : AbpModule @@ -80,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 new file mode 100644 index 0000000000..39bed90383 --- /dev/null +++ b/src/Volo.Abp.Account.Web/AbpAccountWebModule.cs @@ -0,0 +1,39 @@ +using System.Reflection; +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) + { + services.AddAssemblyOf(); + + services.Configure(options => + { + options.Sources.Add( + new EmbeddedFileSet( + "/Areas/", + GetType().GetTypeInfo().Assembly, + "Volo.Abp.Account.Web.Areas" + ) + ); + + options.Sources.Add( + new EmbeddedFileSet( + "/", + GetType().GetTypeInfo().Assembly, + "Volo.Abp.Account.Web.wwwroot" + ) + ); + }); + } + } +} 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 new file mode 100644 index 0000000000..affdbca2c5 --- /dev/null +++ b/src/Volo.Abp.Account.Web/Areas/Account/Controllers/LoginController.cs @@ -0,0 +1,49 @@ +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 : 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 new file mode 100644 index 0000000000..155af50a68 --- /dev/null +++ b/src/Volo.Abp.Account.Web/Areas/Account/Views/Login/Index.cshtml @@ -0,0 +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 new file mode 100644 index 0000000000..cff7fb67a5 --- /dev/null +++ b/src/Volo.Abp.Account.Web/Volo.Abp.Account.Web.csproj @@ -0,0 +1,30 @@ + + + + + + netstandard2.0 + Volo.Abp.Account.Web + Volo.Abp.Account.Web + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + Volo.Abp.Account.Web + + + + + + + + + + + + + + + + + diff --git a/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/AbpAspNetCoreMvcUiBootstrapModule.cs b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/AbpAspNetCoreMvcUiBootstrapModule.cs index b2170d5f67..6a04880e42 100644 --- a/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/AbpAspNetCoreMvcUiBootstrapModule.cs +++ b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/AbpAspNetCoreMvcUiBootstrapModule.cs @@ -16,8 +16,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap services.Configure(options => { - //TODO: Move libs under wwwroot! - options.Sources.Add( new EmbeddedFileSet( "/", 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.AspNetCore.Mvc.UI.Bootstrap/Views/Shared/_AppLayout.cshtml b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/Views/Shared/_AppLayout.cshtml index 446b695822..b8231d799e 100644 --- a/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/Views/Shared/_AppLayout.cshtml +++ b/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/Views/Shared/_AppLayout.cshtml @@ -10,7 +10,7 @@ - Fixed top navbar example for Bootstrap + ABP Web Application 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 af2150a6cf..b1912745b0 100644 --- a/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs +++ b/src/Volo.Abp.Identity.Application/Volo/Abp/Identity/IdentityUserAppService.cs @@ -66,8 +66,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/AbpIdentityWebModule.cs b/src/Volo.Abp.Identity.Web/AbpIdentityWebModule.cs index 02dfc85976..661127fdd8 100644 --- a/src/Volo.Abp.Identity.Web/AbpIdentityWebModule.cs +++ b/src/Volo.Abp.Identity.Web/AbpIdentityWebModule.cs @@ -1,6 +1,6 @@ using System.Reflection; using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap; using Volo.Abp.EmbeddedFiles; using Volo.Abp.Identity.Web.Navigation; using Volo.Abp.Modularity; @@ -8,9 +8,8 @@ using Volo.Abp.Ui.Navigation; namespace Volo.Abp.Identity.Web { - [DependsOn(typeof(AbpAspNetCoreMvcModule))] [DependsOn(typeof(AbpIdentityApplicationContractsModule))] - [DependsOn(typeof(AbpAspNetCoreMvcUiModule))] + [DependsOn(typeof(AbpAspNetCoreMvcUiBootstrapModule))] public class AbpIdentityWebModule : AbpModule { public override void ConfigureServices(IServiceCollection services) 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 48ab86f57a..b14c3ca582 100644 --- a/src/Volo.Abp.Identity.Web/Areas/Identity/Controllers/UsersController.cs +++ b/src/Volo.Abp.Identity.Web/Areas/Identity/Controllers/UsersController.cs @@ -1,11 +1,13 @@ -using System; +using System; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc; namespace Volo.Abp.Identity.Web.Areas.Identity.Controllers { [Area("Identity")] + [Authorize] public class UsersController : AbpController { private readonly IIdentityUserAppService _identityUserAppService; diff --git a/src/Volo.Abp.Identity.Web/Volo.Abp.Identity.Web.csproj b/src/Volo.Abp.Identity.Web/Volo.Abp.Identity.Web.csproj index efe55cc4a5..8351793d79 100644 --- a/src/Volo.Abp.Identity.Web/Volo.Abp.Identity.Web.csproj +++ b/src/Volo.Abp.Identity.Web/Volo.Abp.Identity.Web.csproj @@ -24,8 +24,7 @@ - - +