From 91193c664a99369a92b45b9be26398bbca925dac Mon Sep 17 00:00:00 2001 From: maliming Date: Thu, 7 Apr 2022 18:06:44 +0800 Subject: [PATCH] Add `Volo.Abp.Account.Web.OpenIddict` package. --- modules/account/Volo.Abp.Account.sln | 7 + .../Properties/launchSettings.json | 27 ---- .../AbpAccountWebOpenIddictModule.cs | 29 ++++ .../FodyWeavers.xml | 3 + .../FodyWeavers.xsd | 30 ++++ .../Account/OpenIddictSupportedLoginModel.cs | 134 ++++++++++++++++++ .../Pages/_ViewImports.cshtml | 4 + .../Volo.Abp.Account.Web.OpenIddict.csproj | 34 +++++ .../Pages/Account/Login.cshtml.cs | 5 +- .../OpenIddict.Demo.Server.csproj | 2 +- .../OpenIddictServerModule.cs | 2 +- .../Controllers/AuthorizeController.cs | 1 - .../Controllers/LogoutController.cs | 19 ++- .../Views/Authorize/Authorize.cshtml | 4 +- .../Abp/OpenIddict/Views/Logout/Logout.cshtml | 3 +- nupkg/common.ps1 | 1 + 16 files changed, 265 insertions(+), 40 deletions(-) delete mode 100644 modules/account/src/Volo.Abp.Account.Web.IdentityServer/Properties/launchSettings.json create mode 100644 modules/account/src/Volo.Abp.Account.Web.OpenIddict/AbpAccountWebOpenIddictModule.cs create mode 100644 modules/account/src/Volo.Abp.Account.Web.OpenIddict/FodyWeavers.xml create mode 100644 modules/account/src/Volo.Abp.Account.Web.OpenIddict/FodyWeavers.xsd create mode 100644 modules/account/src/Volo.Abp.Account.Web.OpenIddict/Pages/Account/OpenIddictSupportedLoginModel.cs create mode 100644 modules/account/src/Volo.Abp.Account.Web.OpenIddict/Pages/_ViewImports.cshtml create mode 100644 modules/account/src/Volo.Abp.Account.Web.OpenIddict/Volo.Abp.Account.Web.OpenIddict.csproj diff --git a/modules/account/Volo.Abp.Account.sln b/modules/account/Volo.Abp.Account.sln index 019ed12315..3fe56c6f53 100644 --- a/modules/account/Volo.Abp.Account.sln +++ b/modules/account/Volo.Abp.Account.sln @@ -25,6 +25,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Account.Blazor", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Account.Installer", "src\Volo.Abp.Account.Installer\Volo.Abp.Account.Installer.csproj", "{EAAB416C-9113-486D-9B54-4DCF78FDC6AB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Account.Web.OpenIddict", "src\Volo.Abp.Account.Web.OpenIddict\Volo.Abp.Account.Web.OpenIddict.csproj", "{53DA9051-4C76-4264-A1E1-2810DC685CB2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -67,6 +69,10 @@ Global {EAAB416C-9113-486D-9B54-4DCF78FDC6AB}.Debug|Any CPU.Build.0 = Debug|Any CPU {EAAB416C-9113-486D-9B54-4DCF78FDC6AB}.Release|Any CPU.ActiveCfg = Release|Any CPU {EAAB416C-9113-486D-9B54-4DCF78FDC6AB}.Release|Any CPU.Build.0 = Release|Any CPU + {53DA9051-4C76-4264-A1E1-2810DC685CB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {53DA9051-4C76-4264-A1E1-2810DC685CB2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {53DA9051-4C76-4264-A1E1-2810DC685CB2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {53DA9051-4C76-4264-A1E1-2810DC685CB2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -81,6 +87,7 @@ Global {356EAC51-5D55-4852-A8A5-2F90EAC8DAE3} = {12FAE513-7575-4235-89DF-277BA1A3B098} {EE8858B3-A638-481B-8EB9-74F5E7D43D80} = {B5881429-EFF7-4F30-8C0B-0AC41E36B74E} {EAAB416C-9113-486D-9B54-4DCF78FDC6AB} = {B5881429-EFF7-4F30-8C0B-0AC41E36B74E} + {53DA9051-4C76-4264-A1E1-2810DC685CB2} = {B5881429-EFF7-4F30-8C0B-0AC41E36B74E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {2B054393-D2B2-4EA8-8A15-D60CBCF3E7A9} diff --git a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Properties/launchSettings.json b/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Properties/launchSettings.json deleted file mode 100644 index b25b2e4e3d..0000000000 --- a/modules/account/src/Volo.Abp.Account.Web.IdentityServer/Properties/launchSettings.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:2922/", - "sslPort": 44394 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "Volo.Abp.Account.Web.IdentityServer": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:5001;http://localhost:5000" - } - } -} \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Web.OpenIddict/AbpAccountWebOpenIddictModule.cs b/modules/account/src/Volo.Abp.Account.Web.OpenIddict/AbpAccountWebOpenIddictModule.cs new file mode 100644 index 0000000000..7a81943dd3 --- /dev/null +++ b/modules/account/src/Volo.Abp.Account.Web.OpenIddict/AbpAccountWebOpenIddictModule.cs @@ -0,0 +1,29 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Modularity; +using Volo.Abp.OpenIddict; +using Volo.Abp.VirtualFileSystem; + +namespace Volo.Abp.Account.Web; + +[DependsOn( + typeof(AbpAccountWebModule), + typeof(AbpOpenIddictAspNetCoreModule) +)] +public class AbpAccountWebOpenIddictModule : AbpModule +{ + public override void PreConfigureServices(ServiceConfigurationContext context) + { + PreConfigure(mvcBuilder => + { + mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpAccountWebOpenIddictModule).Assembly); + }); + } + + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + } +} diff --git a/modules/account/src/Volo.Abp.Account.Web.OpenIddict/FodyWeavers.xml b/modules/account/src/Volo.Abp.Account.Web.OpenIddict/FodyWeavers.xml new file mode 100644 index 0000000000..be0de3a908 --- /dev/null +++ b/modules/account/src/Volo.Abp.Account.Web.OpenIddict/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Web.OpenIddict/FodyWeavers.xsd b/modules/account/src/Volo.Abp.Account.Web.OpenIddict/FodyWeavers.xsd new file mode 100644 index 0000000000..3f3946e282 --- /dev/null +++ b/modules/account/src/Volo.Abp.Account.Web.OpenIddict/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Web.OpenIddict/Pages/Account/OpenIddictSupportedLoginModel.cs b/modules/account/src/Volo.Abp.Account.Web.OpenIddict/Pages/Account/OpenIddictSupportedLoginModel.cs new file mode 100644 index 0000000000..c6f9ddad71 --- /dev/null +++ b/modules/account/src/Volo.Abp.Account.Web.OpenIddict/Pages/Account/OpenIddictSupportedLoginModel.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.Options; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using OpenIddict.Abstractions; +using OpenIddict.Server; +using OpenIddict.Server.AspNetCore; +using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.Account.Web.Pages.Account; + +[ExposeServices(typeof(LoginModel))] +public class OpenIddictSupportedLoginModel : LoginModel +{ + public OpenIddictSupportedLoginModel( + IAuthenticationSchemeProvider schemeProvider, + IOptions accountOptions, + IOptions identityOptions) + : base(schemeProvider, accountOptions, identityOptions) + { + } + + public async override Task OnGetAsync() + { + LoginInput = new LoginInputModel(); + + var request = await GetOpenIddictRequestFromReturnUrlAsync(ReturnUrl); + if (request?.ClientId != null) + { + ShowCancelButton = true; + + LoginInput.UserNameOrEmailAddress = request.LoginHint; + + //TODO: Reference AspNetCore MultiTenancy module and use options to get the tenant key! + var tenant = request.GetParameter(TenantResolverConsts.DefaultTenantKey)?.ToString(); + if (!string.IsNullOrEmpty(tenant)) + { + CurrentTenant.Change(Guid.Parse(tenant)); + Response.Cookies.Append(TenantResolverConsts.DefaultTenantKey, tenant); + } + } + + return await base.OnGetAsync(); + } + + public async override Task OnPostAsync(string action) + { + if (action == "Cancel") + { + var request = await GetOpenIddictRequestFromReturnUrlAsync(ReturnUrl); + if (request?.ClientId == null) + { + return Redirect("~/"); + } + + var transaction = HttpContext.Features.Get()?.Transaction; + + transaction.EndpointType = OpenIddictServerEndpointType.Authorization; + transaction.Request = request; + + var notification = new OpenIddictServerEvents.ValidateAuthorizationRequestContext(transaction); + transaction.SetProperty(typeof(OpenIddictServerEvents.ValidateAuthorizationRequestContext).FullName!, notification); + + return Forbid(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); + } + + return await base.OnPostAsync(action); + } + + protected virtual Task GetOpenIddictRequestFromReturnUrlAsync(string returnUrl) + { + if (!returnUrl.IsNullOrWhiteSpace()) + { + var qm = returnUrl.IndexOf("?", StringComparison.Ordinal); + if (qm > 0) + { + return Task.FromResult(new OpenIddictRequest(returnUrl.Substring(qm + 1) + .Split("&") + .Select(x => + x.Split("=").Length == 2 + ? new KeyValuePair(x.Split("=")[0], WebUtility.UrlDecode(x.Split("=")[1])) + : new KeyValuePair(null, null)) + .Where(x => x.Key != null))); + } + } + + return Task.FromResult(null); + } + + public async override Task OnPostExternalLogin(string provider) + { + if (AccountOptions.WindowsAuthenticationSchemeName == provider) + { + return await ProcessWindowsLoginAsync(); + } + + return await base.OnPostExternalLogin(provider); + } + + protected virtual async Task ProcessWindowsLoginAsync() + { + var result = await HttpContext.AuthenticateAsync(AccountOptions.WindowsAuthenticationSchemeName); + if (result.Succeeded) + { + var props = new AuthenticationProperties() + { + RedirectUri = Url.Page("./Login", pageHandler: "ExternalLoginCallback", values: new { ReturnUrl, ReturnUrlHash }), + Items = + { + { + "LoginProvider", AccountOptions.WindowsAuthenticationSchemeName + } + } + }; + + var id = new ClaimsIdentity(AccountOptions.WindowsAuthenticationSchemeName); + id.AddClaim(new Claim(ClaimTypes.NameIdentifier, result.Principal.FindFirstValue(ClaimTypes.PrimarySid))); + id.AddClaim(new Claim(ClaimTypes.Name, result.Principal.FindFirstValue(ClaimTypes.Name))); + + await HttpContext.SignInAsync(IdentityConstants.ExternalScheme, new ClaimsPrincipal(id), props); + + return Redirect(props.RedirectUri!); + } + + return Challenge(AccountOptions.WindowsAuthenticationSchemeName); + } +} diff --git a/modules/account/src/Volo.Abp.Account.Web.OpenIddict/Pages/_ViewImports.cshtml b/modules/account/src/Volo.Abp.Account.Web.OpenIddict/Pages/_ViewImports.cshtml new file mode 100644 index 0000000000..c1da1f5f10 --- /dev/null +++ b/modules/account/src/Volo.Abp.Account.Web.OpenIddict/Pages/_ViewImports.cshtml @@ -0,0 +1,4 @@ +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers +@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI +@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap +@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling \ No newline at end of file diff --git a/modules/account/src/Volo.Abp.Account.Web.OpenIddict/Volo.Abp.Account.Web.OpenIddict.csproj b/modules/account/src/Volo.Abp.Account.Web.OpenIddict/Volo.Abp.Account.Web.OpenIddict.csproj new file mode 100644 index 0000000000..1d801d5f6e --- /dev/null +++ b/modules/account/src/Volo.Abp.Account.Web.OpenIddict/Volo.Abp.Account.Web.OpenIddict.csproj @@ -0,0 +1,34 @@ + + + + + + + net6.0 + Volo.Abp.Account.Web.OpenIddict + Volo.Abp.Account.Web.OpenIddict + true + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + true + Volo.Abp.Account.Web + Library + + + + + + + + + + + + + + + + + diff --git a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs index 5ec85d4078..9d6e2d8b9b 100644 --- a/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs +++ b/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml.cs @@ -75,8 +75,7 @@ public class LoginModel : AccountPageModel if (IsExternalLoginOnly) { - //return await ExternalLogin(vm.ExternalLoginScheme, returnUrl); - throw new NotImplementedException(); + return await OnPostExternalLogin(ExternalProviders.First().AuthenticationScheme); } return Page(); @@ -277,7 +276,7 @@ public class LoginModel : AccountPageModel CheckIdentityErrors(await UserManager.SetEmailAsync(user, emailAddress)); CheckIdentityErrors(await UserManager.AddLoginAsync(user, info)); CheckIdentityErrors(await UserManager.AddDefaultRolesAsync(user)); - + user.Name = info.Principal.FindFirstValue(AbpClaimTypes.Name); user.Surname = info.Principal.FindFirstValue(AbpClaimTypes.SurName); diff --git a/modules/openiddict/app/OpenIddict.Demo.Server/OpenIddict.Demo.Server.csproj b/modules/openiddict/app/OpenIddict.Demo.Server/OpenIddict.Demo.Server.csproj index d2af33ab2e..5ec9575ad3 100644 --- a/modules/openiddict/app/OpenIddict.Demo.Server/OpenIddict.Demo.Server.csproj +++ b/modules/openiddict/app/OpenIddict.Demo.Server/OpenIddict.Demo.Server.csproj @@ -22,7 +22,7 @@ - + diff --git a/modules/openiddict/app/OpenIddict.Demo.Server/OpenIddictServerModule.cs b/modules/openiddict/app/OpenIddict.Demo.Server/OpenIddictServerModule.cs index cbcf45e457..39b2e715ff 100644 --- a/modules/openiddict/app/OpenIddict.Demo.Server/OpenIddictServerModule.cs +++ b/modules/openiddict/app/OpenIddict.Demo.Server/OpenIddictServerModule.cs @@ -46,7 +46,7 @@ namespace OpenIddict.Demo.Server; typeof(AbpAccountApplicationModule), typeof(AbpAccountHttpApiModule), - typeof(AbpAccountWebModule), + typeof(AbpAccountWebOpenIddictModule), typeof(AbpTenantManagementApplicationModule), typeof(AbpTenantManagementHttpApiModule), diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/AuthorizeController.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/AuthorizeController.cs index 094a65e228..59bf83b18f 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/AuthorizeController.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/AuthorizeController.cs @@ -232,5 +232,4 @@ public class AuthorizeController : AbpOpenIdDictControllerBase // to redirect the user agent to the client application using the appropriate response_mode. return Task.FromResult(Forbid(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)); } - } diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/LogoutController.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/LogoutController.cs index 202a4f7483..158fe9896d 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/LogoutController.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/LogoutController.cs @@ -1,5 +1,6 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using OpenIddict.Server.AspNetCore; @@ -15,6 +16,7 @@ public class LogoutController : AbpOpenIdDictControllerBase } [HttpPost] + [AbpFormValueRequired("submit.Accept")] public virtual async Task HandleAcceptAsync() { // Ask ASP.NET Core Identity to delete the local and external cookies created @@ -27,9 +29,18 @@ public class LogoutController : AbpOpenIdDictControllerBase // the RedirectUri specified in the authentication properties if none was set. return SignOut( authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, - properties: new AuthenticationProperties - { - RedirectUri = "/" - }); + properties: new AuthenticationProperties {RedirectUri = "/"}); + } + + [HttpPost] + [AbpFormValueRequired("submit.Deny")] + public virtual Task HandleDenyConsentAsync() + { + // Returning a SignOutResult will ask OpenIddict to redirect the user agent + // to the post_logout_redirect_uri specified by the client application or to + // the RedirectUri specified in the authentication properties if none was set. + return Task.FromResult(SignOut( + authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, + properties: new AuthenticationProperties {RedirectUri = "/"})); } } diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Views/Authorize/Authorize.cshtml b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Views/Authorize/Authorize.cshtml index 31c8b1e665..91aecd60a2 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Views/Authorize/Authorize.cshtml +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Views/Authorize/Authorize.cshtml @@ -17,7 +17,7 @@ } - - + + diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Views/Logout/Logout.cshtml b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Views/Logout/Logout.cshtml index 6f0b398643..8ab7af1a57 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Views/Logout/Logout.cshtml +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Views/Logout/Logout.cshtml @@ -16,6 +16,7 @@ } - + + diff --git a/nupkg/common.ps1 b/nupkg/common.ps1 index f9a40d6729..48f3cf9114 100644 --- a/nupkg/common.ps1 +++ b/nupkg/common.ps1 @@ -230,6 +230,7 @@ $projects = ( "modules/account/src/Volo.Abp.Account.HttpApi", "modules/account/src/Volo.Abp.Account.Web", "modules/account/src/Volo.Abp.Account.Web.IdentityServer", + "modules/account/src/Volo.Abp.Account.Web.OpenIddict", "modules/account/src/Volo.Abp.Account.Blazor", "modules/account/src/Volo.Abp.Account.Installer", "studio/source-codes/Volo.Abp.Account.SourceCode",