From a6014e56727c2122d791e734ff5001ef13488adf Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 15 Apr 2022 16:20:52 +0800 Subject: [PATCH] Refactor --- .../Account/OpenIddictSupportedLoginModel.cs | 36 +++++-------------- .../AbpOpenIddictHttpContextExtensions.cs | 14 ++++++++ .../OpenIddict/AbpOpenIddictRequestHelper.cs | 32 +++++++++++++++++ .../AbpOpenIddictClaimDestinationsManager.cs | 32 +++++++++++++++++ .../AbpOpenIdDictControllerBase.cs | 13 ++----- .../Controllers/AuthorizeController.cs | 4 +-- .../OpenIddict/Controllers/TokenController.cs | 15 ++++++-- .../AbpOpenIddictExtensionGrantsOptions.cs | 20 +++++++++++ .../ExtensionGrantContext.cs | 17 +++++++++ .../ExtensionGrantTypes/IExtensionGrant.cs | 11 ++++++ .../ITokenExtensionGrant.cs | 6 ++++ 11 files changed, 158 insertions(+), 42 deletions(-) create mode 100644 modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictHttpContextExtensions.cs create mode 100644 modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictRequestHelper.cs create mode 100644 modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/AbpOpenIddictClaimDestinationsManager.cs create mode 100644 modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ExtensionGrantTypes/AbpOpenIddictExtensionGrantsOptions.cs create mode 100644 modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ExtensionGrantTypes/ExtensionGrantContext.cs create mode 100644 modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ExtensionGrantTypes/IExtensionGrant.cs create mode 100644 modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ExtensionGrantTypes/ITokenExtensionGrant.cs 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 index 7e3ff1817a..61b170c612 100644 --- 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 @@ -1,37 +1,37 @@ 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; +using Volo.Abp.OpenIddict; namespace Volo.Abp.Account.Web.Pages.Account; [ExposeServices(typeof(LoginModel))] public class OpenIddictSupportedLoginModel : LoginModel { + protected AbpOpenIddictRequestHelper OpenIddictRequestHelper { get; } public OpenIddictSupportedLoginModel( IAuthenticationSchemeProvider schemeProvider, IOptions accountOptions, - IOptions identityOptions) + IOptions identityOptions, + AbpOpenIddictRequestHelper openIddictRequestHelper) : base(schemeProvider, accountOptions, identityOptions) { + OpenIddictRequestHelper = openIddictRequestHelper; } public async override Task OnGetAsync() { LoginInput = new LoginInputModel(); - var request = await GetOpenIddictRequestFromReturnUrlAsync(ReturnUrl); + var request = await OpenIddictRequestHelper.GetFromReturnUrlAsync(ReturnUrl); if (request?.ClientId != null) { ShowCancelButton = true; @@ -54,9 +54,9 @@ public class OpenIddictSupportedLoginModel : LoginModel { if (action == "Cancel") { - var request = await GetOpenIddictRequestFromReturnUrlAsync(ReturnUrl); + var request = await OpenIddictRequestHelper.GetFromReturnUrlAsync(ReturnUrl); - var transaction = HttpContext.Features.Get()?.Transaction; + var transaction = HttpContext.GetOpenIddictServerTransaction(); if (request?.ClientId != null && transaction != null) { transaction.EndpointType = OpenIddictServerEndpointType.Authorization; @@ -74,26 +74,6 @@ public class OpenIddictSupportedLoginModel : LoginModel 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) diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictHttpContextExtensions.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictHttpContextExtensions.cs new file mode 100644 index 0000000000..a6ace40ba1 --- /dev/null +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictHttpContextExtensions.cs @@ -0,0 +1,14 @@ +using Microsoft.AspNetCore.Http; +using OpenIddict.Server; +using OpenIddict.Server.AspNetCore; + +namespace Volo.Abp.OpenIddict; + +public static class AbpOpenIddictHttpContextExtensions +{ + public static OpenIddictServerTransaction GetOpenIddictServerTransaction(this HttpContext context) + { + Check.NotNull(context, nameof(context)); + return context.Features.Get()?.Transaction; + } +} diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictRequestHelper.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictRequestHelper.cs new file mode 100644 index 0000000000..d4913b8a0c --- /dev/null +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/AbpOpenIddictRequestHelper.cs @@ -0,0 +1,32 @@ +using System; +using System.Threading.Tasks; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using OpenIddict.Abstractions; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.OpenIddict; + +public class AbpOpenIddictRequestHelper : ITransientDependency +{ + public virtual Task GetFromReturnUrlAsync(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); + } +} diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/AbpOpenIddictClaimDestinationsManager.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/AbpOpenIddictClaimDestinationsManager.cs new file mode 100644 index 0000000000..2974f8ba1d --- /dev/null +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ClaimDestinations/AbpOpenIddictClaimDestinationsManager.cs @@ -0,0 +1,32 @@ +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.OpenIddict; + +public class AbpOpenIddictClaimDestinationsManager : ISingletonDependency +{ + protected IServiceScopeFactory ServiceScopeFactory { get; } + protected IOptions Options { get; } + + public AbpOpenIddictClaimDestinationsManager(IServiceScopeFactory serviceScopeFactory, IOptions options) + { + ServiceScopeFactory = serviceScopeFactory; + Options = options; + } + + public virtual async Task SetAsync(ClaimsPrincipal principal) + { + using (var scope = ServiceScopeFactory.CreateScope()) + { + foreach (var providerType in Options.Value.ClaimDestinationsProvider) + { + var provider = (IAbpOpenIddictClaimDestinationsProvider)scope.ServiceProvider.GetRequiredService(providerType); + await provider.SetDestinationsAsync(new AbpOpenIddictClaimDestinationsProviderContext(scope.ServiceProvider, principal, principal.Claims.ToArray())); + } + } + } +} diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/AbpOpenIdDictControllerBase.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/AbpOpenIdDictControllerBase.cs index a658181077..68e0418ec1 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/AbpOpenIdDictControllerBase.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/AbpOpenIdDictControllerBase.cs @@ -25,14 +25,14 @@ public abstract class AbpOpenIdDictControllerBase : AbpController protected IOpenIddictAuthorizationManager AuthorizationManager => LazyServiceProvider.LazyGetRequiredService(); protected IOpenIddictScopeManager ScopeManager => LazyServiceProvider.LazyGetRequiredService(); protected IOpenIddictTokenManager TokenManager => LazyServiceProvider.LazyGetRequiredService(); - protected IOptions OpenIddictClaimDestinationsOptions => LazyServiceProvider.LazyGetRequiredService>(); + protected AbpOpenIddictClaimDestinationsManager OpenIddictClaimDestinationsManager => LazyServiceProvider.LazyGetRequiredService(); protected AbpOpenIdDictControllerBase() { LocalizationResource = typeof(AbpOpenIddictResource); } - protected virtual Task GetOpenIddictServerRequest(HttpContext httpContext) + protected virtual Task GetOpenIddictServerRequestAsync(HttpContext httpContext) { var request = HttpContext.GetOpenIddictServerRequest() ?? throw new InvalidOperationException(L["TheOpenIDConnectRequestCannotBeRetrieved"]); @@ -57,13 +57,6 @@ public abstract class AbpOpenIdDictControllerBase : AbpController protected virtual async Task SetClaimsDestinationsAsync(ClaimsPrincipal principal) { - using (var scope = LazyServiceProvider.LazyGetRequiredService().CreateScope()) - { - foreach (var providerType in OpenIddictClaimDestinationsOptions.Value.ClaimDestinationsProvider) - { - var provider = (IAbpOpenIddictClaimDestinationsProvider)scope.ServiceProvider.GetRequiredService(providerType); - await provider.SetDestinationsAsync(new AbpOpenIddictClaimDestinationsProviderContext(scope.ServiceProvider, principal, principal.Claims.ToArray())); - } - } + await OpenIddictClaimDestinationsManager.SetAsync(principal); } } 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 b94a3dacb8..cf06c05933 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 @@ -22,7 +22,7 @@ public class AuthorizeController : AbpOpenIdDictControllerBase [IgnoreAntiforgeryToken] public virtual async Task HandleAsync() { - var request = await GetOpenIddictServerRequest(HttpContext); + var request = await GetOpenIddictServerRequestAsync(HttpContext); // If prompt=login was specified by the client application, // immediately return the user agent to the login page. @@ -162,7 +162,7 @@ public class AuthorizeController : AbpOpenIdDictControllerBase [Authorize, AbpFormValueRequired("submit.Accept")] public virtual async Task HandleAcceptConsentAsync() { - var request = await GetOpenIddictServerRequest(HttpContext); + var request = await GetOpenIddictServerRequestAsync(HttpContext); // Retrieve the profile of the logged in user. var user = await UserManager.GetUserAsync(User) ?? diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.cs index b5a8b41327..4ed6927fd4 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.cs @@ -1,6 +1,10 @@ -using System.Threading.Tasks; +using System.Linq; +using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using OpenIddict.Abstractions; +using Volo.Abp.OpenIddict.ExtensionGrantTypes; namespace Volo.Abp.OpenIddict.Controllers; @@ -10,7 +14,7 @@ public partial class TokenController : AbpOpenIdDictControllerBase [HttpGet, HttpPost, Produces("application/json")] public virtual async Task HandleAsync() { - var request = await GetOpenIddictServerRequest(HttpContext); + var request = await GetOpenIddictServerRequestAsync(HttpContext); if (request.IsPasswordGrantType()) { @@ -37,6 +41,13 @@ public partial class TokenController : AbpOpenIdDictControllerBase return await HandleClientCredentialsAsync(request); } + var extensionGrantsOptions = HttpContext.RequestServices.GetRequiredService>(); + var extensionTokenGrant = extensionGrantsOptions.Value.Find(request.GrantType); + if (extensionTokenGrant != null) + { + return await extensionTokenGrant.HandleAsync(new ExtensionGrantContext(HttpContext, request)); + } + throw new AbpException(string.Format(L["TheSpecifiedGrantTypeIsNotImplemented"], request.GrantType)); } } diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ExtensionGrantTypes/AbpOpenIddictExtensionGrantsOptions.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ExtensionGrantTypes/AbpOpenIddictExtensionGrantsOptions.cs new file mode 100644 index 0000000000..b9017dfb7e --- /dev/null +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ExtensionGrantTypes/AbpOpenIddictExtensionGrantsOptions.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Volo.Abp.OpenIddict.ExtensionGrantTypes; + +public class AbpOpenIddictExtensionGrantsOptions +{ + public Dictionary Grants { get; } + + public AbpOpenIddictExtensionGrantsOptions() + { + Grants = new Dictionary(); + } + + public TExtensionGrantType Find(string name) + where TExtensionGrantType : IExtensionGrant + { + return (TExtensionGrantType)Grants.FirstOrDefault(x => x.Key == name && x.Value is TExtensionGrantType).Value; + } +} diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ExtensionGrantTypes/ExtensionGrantContext.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ExtensionGrantTypes/ExtensionGrantContext.cs new file mode 100644 index 0000000000..00f9444d14 --- /dev/null +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ExtensionGrantTypes/ExtensionGrantContext.cs @@ -0,0 +1,17 @@ +using Microsoft.AspNetCore.Http; +using OpenIddict.Abstractions; + +namespace Volo.Abp.OpenIddict.ExtensionGrantTypes; + +public class ExtensionGrantContext +{ + public HttpContext HttpContext { get; } + + public OpenIddictRequest Request { get; } + + public ExtensionGrantContext(HttpContext httpContext, OpenIddictRequest request) + { + HttpContext = httpContext; + Request = request; + } +} diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ExtensionGrantTypes/IExtensionGrant.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ExtensionGrantTypes/IExtensionGrant.cs new file mode 100644 index 0000000000..5bfaddc0e3 --- /dev/null +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ExtensionGrantTypes/IExtensionGrant.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; + +namespace Volo.Abp.OpenIddict.ExtensionGrantTypes; + +public interface IExtensionGrant +{ + string Name { get; } + + Task HandleAsync(ExtensionGrantContext context); +} diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ExtensionGrantTypes/ITokenExtensionGrant.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ExtensionGrantTypes/ITokenExtensionGrant.cs new file mode 100644 index 0000000000..6e153c91fe --- /dev/null +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/ExtensionGrantTypes/ITokenExtensionGrant.cs @@ -0,0 +1,6 @@ +namespace Volo.Abp.OpenIddict.ExtensionGrantTypes; + +public interface ITokenExtensionGrant : IExtensionGrant +{ + +}