diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerBuilderExtensions.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerBuilderExtensions.cs index 9763ad35f0..d144208c02 100644 --- a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerBuilderExtensions.cs +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerBuilderExtensions.cs @@ -1,17 +1,21 @@ using System; using System.IdentityModel.Tokens.Jwt; using System.IO; +using System.Linq; using System.Security.Cryptography; using IdentityModel; using IdentityServer4; using IdentityServer4.Configuration; using IdentityServer4.Services; +using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Newtonsoft.Json.Linq; +using Volo.Abp.DependencyInjection; using Volo.Abp.Identity; using Volo.Abp.IdentityServer.AspNetIdentity; using Volo.Abp.Security.Claims; +using IdentityUser = Volo.Abp.Identity.IdentityUser; namespace Volo.Abp.IdentityServer { @@ -32,6 +36,10 @@ namespace Volo.Abp.IdentityServer builder.AddAspNetIdentity(); builder.AddProfileService(); builder.AddResourceOwnerValidator(); + + builder.Services.Remove(builder.Services.LastOrDefault(x => x.ServiceType == typeof(IUserClaimsPrincipalFactory))); + builder.Services.AddTransient, AbpUserClaimsFactory>(); + builder.Services.AddTransient>, ObjectAccessor>(); } builder.Services.Replace(ServiceDescriptor.Transient()); diff --git a/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpUserClaimsFactory.cs b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpUserClaimsFactory.cs new file mode 100644 index 0000000000..9643655639 --- /dev/null +++ b/modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AspNetIdentity/AbpUserClaimsFactory.cs @@ -0,0 +1,75 @@ +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using IdentityModel; +using Microsoft.AspNetCore.Identity; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Identity; + +namespace Volo.Abp.IdentityServer.AspNetIdentity +{ + public class AbpUserClaimsFactory : IUserClaimsPrincipalFactory + where TUser : class + { + private readonly IObjectAccessor> _inner; + private readonly UserManager _userManager; + + public AbpUserClaimsFactory(IObjectAccessor> inner, + UserManager userManager) + { + _inner = inner; + _userManager = userManager; + } + + public async Task CreateAsync(TUser user) + { + var principal = await _inner.Value.CreateAsync(user); + var identity = principal.Identities.First(); + + if (!identity.HasClaim(x => x.Type == JwtClaimTypes.Subject)) + { + var sub = await _userManager.GetUserIdAsync(user); + identity.AddIfNotContains(new Claim(JwtClaimTypes.Subject, sub)); + } + + var username = await _userManager.GetUserNameAsync(user); + var usernameClaim = identity.FindFirst(claim => + claim.Type == _userManager.Options.ClaimsIdentity.UserNameClaimType && claim.Value == username); + if (usernameClaim != null) + { + identity.RemoveClaim(usernameClaim); + identity.AddIfNotContains(new Claim(JwtClaimTypes.PreferredUserName, username)); + } + + if (!identity.HasClaim(x => x.Type == JwtClaimTypes.Name)) + { + identity.AddIfNotContains(new Claim(JwtClaimTypes.Name, username)); + } + + if (_userManager.SupportsUserEmail) + { + var email = await _userManager.GetEmailAsync(user); + if (!string.IsNullOrWhiteSpace(email)) + { + identity.AddIfNotContains(new Claim(JwtClaimTypes.Email, email)); + identity.AddIfNotContains(new Claim(JwtClaimTypes.EmailVerified, + await _userManager.IsEmailConfirmedAsync(user) ? "true" : "false", ClaimValueTypes.Boolean)); + } + } + + if (_userManager.SupportsUserPhoneNumber) + { + var phoneNumber = await _userManager.GetPhoneNumberAsync(user); + if (!string.IsNullOrWhiteSpace(phoneNumber)) + { + identity.AddIfNotContains(new Claim(JwtClaimTypes.PhoneNumber, phoneNumber)); + identity.AddIfNotContains(new Claim(JwtClaimTypes.PhoneNumberVerified, + await _userManager.IsPhoneNumberConfirmedAsync(user) ? "true" : "false", + ClaimValueTypes.Boolean)); + } + } + + return principal; + } + } +}