diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs index 295a8bd100..568ecfef7b 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs @@ -1,4 +1,4 @@ -using System; +using System; using JetBrains.Annotations; using Microsoft.AspNetCore.RequestLocalization; using Microsoft.Extensions.DependencyInjection; @@ -6,6 +6,7 @@ using Microsoft.Extensions.Hosting; using Volo.Abp; using Volo.Abp.AspNetCore.Auditing; using Volo.Abp.AspNetCore.ExceptionHandling; +using Volo.Abp.AspNetCore.Security.Claims; using Volo.Abp.AspNetCore.Tracing; using Volo.Abp.AspNetCore.Uow; using Volo.Abp.DependencyInjection; @@ -76,5 +77,10 @@ namespace Microsoft.AspNetCore.Builder app.Properties[ExceptionHandlingMiddlewareMarker] = true; return app.UseMiddleware(); } + + public static IApplicationBuilder UseAbpClaimsMap(this IApplicationBuilder app) + { + return app.UseMiddleware(); + } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpClaimsMapMiddleware.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpClaimsMapMiddleware.cs new file mode 100644 index 0000000000..7740ddfca2 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpClaimsMapMiddleware.cs @@ -0,0 +1,29 @@ +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Security.Claims; + +namespace Volo.Abp.AspNetCore.Security.Claims +{ + public class AbpClaimsMapMiddleware : IMiddleware, ITransientDependency + { + public async Task InvokeAsync(HttpContext context, RequestDelegate next) + { + var currentPrincipalAccessor = context.RequestServices.GetRequiredService(); + var mapOptions = context.RequestServices.GetRequiredService>().Value; + + var mapClaims = currentPrincipalAccessor.Principal.Claims.Where(p => mapOptions.Maps.Keys.Contains(p.Type)); + currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim( + mapOptions.Maps[p.Type], + p.Value, + p.ValueType, + p.Issuer)))); + + await next(context); + } + } +} diff --git a/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpClaimsMapOptions.cs b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpClaimsMapOptions.cs new file mode 100644 index 0000000000..a5eabd76bf --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore/Volo/Abp/AspNetCore/Security/Claims/AbpClaimsMapOptions.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using Volo.Abp.Security.Claims; + +namespace Volo.Abp.AspNetCore.Security.Claims +{ + public class AbpClaimsMapOptions + { + public Dictionary Maps { get; } + + public AbpClaimsMapOptions() + { + Maps = new Dictionary() + { + { "sub", AbpClaimTypes.UserId }, + { "role", AbpClaimTypes.Role }, + { "email", AbpClaimTypes.Email }, + }; + } + } +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs index 90930abc6d..497dd2f45f 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcTestModule.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.Linq; +using System.Security.Claims; using Localization.Resources.AbpUi; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Mvc.ApplicationModels; @@ -8,11 +10,13 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.AspNetCore.Mvc.Authorization; using Volo.Abp.AspNetCore.Mvc.Localization; using Volo.Abp.AspNetCore.Mvc.Localization.Resource; +using Volo.Abp.AspNetCore.Security.Claims; using Volo.Abp.AspNetCore.TestBase; using Volo.Abp.Autofac; using Volo.Abp.Localization; using Volo.Abp.MemoryDb; using Volo.Abp.Modularity; +using Volo.Abp.Security.Claims; using Volo.Abp.TestApp; using Volo.Abp.Validation.Localization; using Volo.Abp.VirtualFileSystem; @@ -76,11 +80,17 @@ namespace Volo.Abp.AspNetCore.Mvc options.Languages.Add(new LanguageInfo("en", "en", "English")); options.Languages.Add(new LanguageInfo("tr", "tr", "Türkçe")); }); - + Configure(options => { options.RootDirectory = "/Volo/Abp/AspNetCore/Mvc"; }); + + Configure(options => + { + options.Maps.Add("SerialNumber", ClaimTypes.SerialNumber); + options.Maps.Add("DateOfBirth", ClaimTypes.DateOfBirth); + }); } public override void OnApplicationInitialization(ApplicationInitializationContext context) @@ -92,6 +102,7 @@ namespace Volo.Abp.AspNetCore.Mvc app.UseAbpRequestLocalization(); app.UseRouting(); app.UseMiddleware(); + app.UseAbpClaimsMap(); app.UseAuthorization(); app.UseAuditing(); app.UseUnitOfWork(); diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Security/Claims/ClaimsMapTestController.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Security/Claims/ClaimsMapTestController.cs new file mode 100644 index 0000000000..d8a4a441fd --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Security/Claims/ClaimsMapTestController.cs @@ -0,0 +1,22 @@ +using System.Security.Claims; +using Microsoft.AspNetCore.Mvc; +using Shouldly; + +namespace Volo.Abp.AspNetCore.Mvc.Security.Claims +{ + public class ClaimsMapTestController : AbpController + { + public ActionResult ClaimsMapTest() + { + var serialNumber = CurrentUser.FindClaim(ClaimTypes.SerialNumber); + serialNumber.ShouldNotBeNull(); + serialNumber.Value.ShouldBe("123456"); + + var dateOfBirth = CurrentUser.FindClaim(ClaimTypes.DateOfBirth); + dateOfBirth.ShouldNotBeNull(); + dateOfBirth.Value.ShouldBe("2020"); + + return Content("OK"); + } + } +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Security/Claims/ClaimsMapTestController_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Security/Claims/ClaimsMapTestController_Tests.cs new file mode 100644 index 0000000000..154956afdf --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Security/Claims/ClaimsMapTestController_Tests.cs @@ -0,0 +1,41 @@ +using System.Security.Claims; +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.AspNetCore.Mvc.Authorization; +using Volo.Abp.AspNetCore.TestBase; +using Volo.Abp.Autofac; +using Volo.Abp.MemoryDb; +using Volo.Abp.Modularity; +using Xunit; + +namespace Volo.Abp.AspNetCore.Mvc.Security.Claims +{ + [DependsOn( + typeof(AbpAspNetCoreTestBaseModule), + typeof(AbpMemoryDbTestModule), + typeof(AbpAspNetCoreMvcModule), + typeof(AbpAutofacModule) + )] + public class ClaimsMapTestController_Tests : AspNetCoreMvcTestBase + { + private readonly FakeUserClaims _fakeRequiredService; + + public ClaimsMapTestController_Tests() + { + _fakeRequiredService = GetRequiredService(); + } + + [Fact] + public async Task Claims_Should_Be_Mapped() + { + _fakeRequiredService.Claims.AddRange(new[] + { + new Claim("SerialNumber", "123456"), + new Claim("DateOfBirth", "2020") + }); + + var result = await GetResponseAsStringAsync("/ClaimsMapTest/ClaimsMapTest"); + result.ShouldBe("OK"); + } + } +} diff --git a/samples/MicroserviceDemo/gateways/BackendAdminAppGateway.Host/BackendAdminAppGatewayHostModule.cs b/samples/MicroserviceDemo/gateways/BackendAdminAppGateway.Host/BackendAdminAppGatewayHostModule.cs index 7edcd7f29a..11dfe16dc3 100644 --- a/samples/MicroserviceDemo/gateways/BackendAdminAppGateway.Host/BackendAdminAppGatewayHostModule.cs +++ b/samples/MicroserviceDemo/gateways/BackendAdminAppGateway.Host/BackendAdminAppGatewayHostModule.cs @@ -110,21 +110,8 @@ namespace BackendAdminAppGateway.Host app.UseVirtualFiles(); app.UseRouting(); app.UseAuthentication(); + app.UseAbpClaimsMap(); - app.Use(async (ctx, next) => - { - var currentPrincipalAccessor = ctx.RequestServices.GetRequiredService(); - var map = new Dictionary() - { - { "sub", AbpClaimTypes.UserId }, - { "role", AbpClaimTypes.Role }, - { "email", AbpClaimTypes.Email }, - //any other map - }; - var mapClaims = currentPrincipalAccessor.Principal.Claims.Where(p => map.Keys.Contains(p.Type)).ToList(); - currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); - await next(); - }); if (MsDemoConsts.IsMultiTenancyEnabled) { app.UseMultiTenancy(); diff --git a/samples/MicroserviceDemo/gateways/InternalGateway.Host/InternalGatewayHostModule.cs b/samples/MicroserviceDemo/gateways/InternalGateway.Host/InternalGatewayHostModule.cs index dcad85fa57..f528957fdf 100644 --- a/samples/MicroserviceDemo/gateways/InternalGateway.Host/InternalGatewayHostModule.cs +++ b/samples/MicroserviceDemo/gateways/InternalGateway.Host/InternalGatewayHostModule.cs @@ -89,21 +89,7 @@ namespace InternalGateway.Host app.UseVirtualFiles(); app.UseRouting(); app.UseAuthentication(); - - app.Use(async (ctx, next) => - { - var currentPrincipalAccessor = ctx.RequestServices.GetRequiredService(); - var map = new Dictionary() - { - { "sub", AbpClaimTypes.UserId }, - { "role", AbpClaimTypes.Role }, - { "email", AbpClaimTypes.Email }, - //any other map - }; - var mapClaims = currentPrincipalAccessor.Principal.Claims.Where(p => map.Keys.Contains(p.Type)).ToList(); - currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); - await next(); - }); + app.UseAbpClaimsMap(); if (MsDemoConsts.IsMultiTenancyEnabled) { app.UseMultiTenancy(); diff --git a/samples/MicroserviceDemo/gateways/PublicWebSiteGateway.Host/PublicWebSiteGatewayHostModule.cs b/samples/MicroserviceDemo/gateways/PublicWebSiteGateway.Host/PublicWebSiteGatewayHostModule.cs index 2bd570d56d..3411598ccf 100644 --- a/samples/MicroserviceDemo/gateways/PublicWebSiteGateway.Host/PublicWebSiteGatewayHostModule.cs +++ b/samples/MicroserviceDemo/gateways/PublicWebSiteGateway.Host/PublicWebSiteGatewayHostModule.cs @@ -85,21 +85,7 @@ namespace PublicWebSiteGateway.Host app.UseVirtualFiles(); app.UseRouting(); app.UseAuthentication(); - - app.Use(async (ctx, next) => - { - var currentPrincipalAccessor = ctx.RequestServices.GetRequiredService(); - var map = new Dictionary() - { - { "sub", AbpClaimTypes.UserId }, - { "role", AbpClaimTypes.Role }, - { "email", AbpClaimTypes.Email }, - //any other map - }; - var mapClaims = currentPrincipalAccessor.Principal.Claims.Where(p => map.Keys.Contains(p.Type)).ToList(); - currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); - await next(); - }); + app.UseAbpClaimsMap(); if (MsDemoConsts.IsMultiTenancyEnabled) { app.UseMultiTenancy(); diff --git a/samples/MicroserviceDemo/microservices/BloggingService.Host/BloggingServiceHostModule.cs b/samples/MicroserviceDemo/microservices/BloggingService.Host/BloggingServiceHostModule.cs index bc9209c72a..3542ec2d5c 100644 --- a/samples/MicroserviceDemo/microservices/BloggingService.Host/BloggingServiceHostModule.cs +++ b/samples/MicroserviceDemo/microservices/BloggingService.Host/BloggingServiceHostModule.cs @@ -121,21 +121,7 @@ namespace BloggingService.Host app.UseVirtualFiles(); app.UseRouting(); app.UseAuthentication(); - - app.Use(async (ctx, next) => - { - var currentPrincipalAccessor = ctx.RequestServices.GetRequiredService(); - var map = new Dictionary() - { - { "sub", AbpClaimTypes.UserId }, - { "role", AbpClaimTypes.Role }, - { "email", AbpClaimTypes.Email }, - //any other map - }; - var mapClaims = currentPrincipalAccessor.Principal.Claims.Where(p => map.Keys.Contains(p.Type)).ToList(); - currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); - await next(); - }); + app.UseAbpClaimsMap(); if (MsDemoConsts.IsMultiTenancyEnabled) { diff --git a/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs b/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs index 457950cba4..9b96532e4c 100644 --- a/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs +++ b/samples/MicroserviceDemo/microservices/IdentityService.Host/IdentityServiceHostModule.cs @@ -102,26 +102,13 @@ namespace IdentityService.Host app.UseVirtualFiles(); app.UseRouting(); app.UseAuthentication(); + app.UseAbpClaimsMap(); if (MsDemoConsts.IsMultiTenancyEnabled) { app.UseMultiTenancy(); } - - app.Use(async (ctx, next) => - { - var currentPrincipalAccessor = ctx.RequestServices.GetRequiredService(); - var map = new Dictionary() - { - { "sub", AbpClaimTypes.UserId }, - { "role", AbpClaimTypes.Role }, - { "email", AbpClaimTypes.Email }, - //any other map - }; - var mapClaims = currentPrincipalAccessor.Principal.Claims.Where(p => map.Keys.Contains(p.Type)).ToList(); - currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); - await next(); - }); + app.UseAbpRequestLocalization(); //TODO: localization? app.UseSwagger(); app.UseSwaggerUI(options => diff --git a/samples/MicroserviceDemo/microservices/ProductService.Host/ProductServiceHostModule.cs b/samples/MicroserviceDemo/microservices/ProductService.Host/ProductServiceHostModule.cs index 4968ce75a4..74a1213a83 100644 --- a/samples/MicroserviceDemo/microservices/ProductService.Host/ProductServiceHostModule.cs +++ b/samples/MicroserviceDemo/microservices/ProductService.Host/ProductServiceHostModule.cs @@ -105,21 +105,7 @@ namespace ProductService.Host app.UseVirtualFiles(); app.UseRouting(); app.UseAuthentication(); - - app.Use(async (ctx, next) => - { - var currentPrincipalAccessor = ctx.RequestServices.GetRequiredService(); - var map = new Dictionary() - { - { "sub", AbpClaimTypes.UserId }, - { "role", AbpClaimTypes.Role }, - { "email", AbpClaimTypes.Email }, - //any other map - }; - var mapClaims = currentPrincipalAccessor.Principal.Claims.Where(p => map.Keys.Contains(p.Type)).ToList(); - currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); - await next(); - }); + app.UseAbpClaimsMap(); if (MsDemoConsts.IsMultiTenancyEnabled) { diff --git a/samples/MicroserviceDemo/microservices/TenantManagementService.Host/TenantManagementServiceHostModule.cs b/samples/MicroserviceDemo/microservices/TenantManagementService.Host/TenantManagementServiceHostModule.cs index 504713c047..8c01363e7d 100644 --- a/samples/MicroserviceDemo/microservices/TenantManagementService.Host/TenantManagementServiceHostModule.cs +++ b/samples/MicroserviceDemo/microservices/TenantManagementService.Host/TenantManagementServiceHostModule.cs @@ -106,21 +106,7 @@ namespace TenantManagementService.Host app.UseVirtualFiles(); app.UseRouting(); app.UseAuthentication(); - - app.Use(async (ctx, next) => - { - var currentPrincipalAccessor = ctx.RequestServices.GetRequiredService(); - var map = new Dictionary() - { - { "sub", AbpClaimTypes.UserId }, - { "role", AbpClaimTypes.Role }, - { "email", AbpClaimTypes.Email }, - //any other map - }; - var mapClaims = currentPrincipalAccessor.Principal.Claims.Where(p => map.Keys.Contains(p.Type)).ToList(); - currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); - await next(); - }); + app.UseAbpClaimsMap(); if (MsDemoConsts.IsMultiTenancyEnabled) { diff --git a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs index fa3ad928f4..14aee9bbfa 100644 --- a/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs +++ b/templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs @@ -168,25 +168,11 @@ namespace MyCompanyName.MyProjectName app.UseRouting(); app.UseCors(DefaultCorsPolicyName); app.UseAuthentication(); - + app.UseAbpClaimsMap(); if (MultiTenancyConsts.IsEnabled) { app.UseMultiTenancy(); } - app.Use(async (ctx, next) => - { - var currentPrincipalAccessor = ctx.RequestServices.GetRequiredService(); - var map = new Dictionary() - { - { "sub", AbpClaimTypes.UserId }, - { "role", AbpClaimTypes.Role }, - { "email", AbpClaimTypes.Email }, - //any other map - }; - var mapClaims = currentPrincipalAccessor.Principal.Claims.Where(p => map.Keys.Contains(p.Type)).ToList(); - currentPrincipalAccessor.Principal.AddIdentity(new ClaimsIdentity(mapClaims.Select(p => new Claim(map[p.Type], p.Value, p.ValueType, p.Issuer)))); - await next(); - }); app.UseAbpRequestLocalization(); app.UseAuthorization(); app.UseSwagger();