hi
You can use UserManager<Volo.Abp.Identity.IdentityUser>
https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.identity.usermanager-1.getloginsasync?view=aspnetcore-6.0
hi
You can try to reach the abp.io in your computer browser.
hi
Unable to get the email of external user!
Try to debug the MapClaimsToExternalLoginUserInfoAsync method. share the values of claims
Configure<AbpIdentityOptions>(options =>
{
options.ExternalLoginProviders.RemoveAll(x => x.Key == "OAuth");
options.ExternalLoginProviders.Add<MyOAuthExternalLoginProvider>(MyOAuthExternalLoginProvider.Name);
});
public class MyOAuthExternalLoginProvider : OAuthExternalLoginProvider
{
public const string Name = "OAuth";
public ILogger<OAuthExternalLoginProvider> Logger { get; set; }
protected OAuthExternalLoginManager OAuthExternalLoginManager { get; }
protected ISettingProvider SettingProvider { get; }
protected IFeatureChecker FeatureChecker { get; }
protected AbpOAuthExternalLoginProviderOptions Options { get; }
public MyOAuthExternalLoginProvider(
IGuidGenerator guidGenerator,
ICurrentTenant currentTenant,
IdentityUserManager userManager,
IIdentityUserRepository identityUserRepository,
IOptions<IdentityOptions> identityOptions,
OAuthExternalLoginManager oAuthExternalLoginManager,
ISettingProvider settingProvider,
IFeatureChecker featureChecker,
IOptions<AbpOAuthExternalLoginProviderOptions> options)
: base(guidGenerator, currentTenant, userManager, identityUserRepository, identityOptions, oAuthExternalLoginManager, settingProvider, featureChecker, options)
{
}
protected override Task<ExternalLoginUserInfo> MapClaimsToExternalLoginUserInfoAsync(IEnumerable<Claim> claims)
{
var claimsArray = claims as Claim[] ?? claims.ToArray();
var email = claimsArray.FirstOrDefault(x => x.Type == Options.EmailClaimType);
if(email == null)
{
throw new Exception("Unable to get the email of external user!");
}
var userInfo = new ExternalLoginUserInfo(email.Value)
{
Name = claimsArray.FirstOrDefault(x => x.Type == Options.NameClaimType)?.Value,
Surname = claimsArray.FirstOrDefault(x => x.Type == Options.SurnameClaimType)?.Value,
EmailConfirmed = claimsArray.FirstOrDefault(x => x.Type == Options.EmailConfirmedClaimType)?.Value.To<bool>() ?? false,
PhoneNumber = claimsArray.FirstOrDefault(x => x.Type == Options.PhoneNumberClaimType)?.Value,
PhoneNumberConfirmed = claimsArray.FirstOrDefault(x => x.Type == Options.PhoneNumberConfirmedClaimType)?.Value.To<bool>() ?? false,
ProviderKey = claimsArray.FirstOrDefault(x => x.Type == Options.ProviderKeyClaimType)?.Value
};
return Task.FromResult(userInfo);
}
}
hi
You can refer to Identity Server documentation, ABP framework has not changed its behavior.
hi
Can you try to use Configure?
Configure<OpenIddictServerAspNetCoreBuilder>(configure =>
{
configure.DisableTransportSecurityRequirement();
});
hi
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.Replace(ServiceDescriptor.Transient<IUserClaimsPrincipalFactory<IdentityUser>, MyUserClaimsFactory<IdentityUser>>());
}
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
using IdentityModel;
using Microsoft.AspNetCore.Identity;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Security.Claims;
using IdentityUser = Volo.Abp.Identity.IdentityUser;
namespace AbpApplicationTemplate;
public class MyUserClaimsFactory<TUser> : IUserClaimsPrincipalFactory<TUser>
where TUser : class
{
private readonly IObjectAccessor<IUserClaimsPrincipalFactory<TUser>> _inner;
private readonly UserManager<TUser> _userManager;
private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor;
private readonly IAbpClaimsPrincipalFactory _abpClaimsPrincipalFactory;
public MyUserClaimsFactory(IObjectAccessor<IUserClaimsPrincipalFactory<TUser>> inner,
UserManager<TUser> userManager, ICurrentPrincipalAccessor currentPrincipalAccessor, IAbpClaimsPrincipalFactory abpClaimsPrincipalFactory)
{
_inner = inner;
_userManager = userManager;
_currentPrincipalAccessor = currentPrincipalAccessor;
_abpClaimsPrincipalFactory = abpClaimsPrincipalFactory;
}
public async Task<ClaimsPrincipal> 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));
//https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/issues/1627
//https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/blob/05e02b5e0383be40e45c667c12f6667d38e33fcc/src/System.IdentityModel.Tokens.Jwt/ClaimTypeMapping.cs#L52
identity.AddIfNotContains(new Claim(JwtRegisteredClaimNames.UniqueName, 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));
}
}
if (user is IdentityUser identityUser)
{
if (!identityUser.Name.IsNullOrEmpty())
{
identity.AddIfNotContains(new Claim(JwtClaimTypes.GivenName, identityUser.Name));
}
if (!identityUser.Surname.IsNullOrEmpty())
{
identity.AddIfNotContains(new Claim(JwtClaimTypes.FamilyName, identityUser.Surname));
}
}
using (_currentPrincipalAccessor.Change(identity))
{
await _abpClaimsPrincipalFactory.CreateAsync(principal);
}
return principal;
}
}
hi
You need to depend on AbpIdentityDomainModule & AbpIdentityEntityFrameworkCoreModule and then inject OrganizationUnitManager .
Where does CmsUser search/ insert during login process takes place? Could you point me to the source file? Maybe overriding it to customize it to my needs is easier than finding the cause of that issue.
hi
CreateUser
https://github.com/abpframework/abp/blob/dev/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Users/CmsUserLookupService.cs
https://github.com/abpframework/abp/blob/dev/modules/users/src/Volo.Abp.Users.Domain/Volo/Abp/Users/UserLookupService.cs
hi
it does not work with version 5.2.2.
Please create a 5.2.2 project and reproduce the problem then share it with me. Thanks
limimg.ma@volosoft.com
hi
I will share the code. Please wait.