Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider adding GetUserInfoAsync(string userName) #21814

Open
1 task done
colinin opened this issue Jan 6, 2025 · 0 comments
Open
1 task done

Consider adding GetUserInfoAsync(string userName) #21814

colinin opened this issue Jan 6, 2025 · 0 comments

Comments

@colinin
Copy link

colinin commented Jan 6, 2025

Is there an existing issue for this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe the problem.

I have an external system, it allows the user to UserCode or UserName to log in, the current IExternalLoginProvider only in one as a login name, because the UserManager.FindByNameAsync(string userName):

if (await externalLoginProvider.TryAuthenticateAsync(userName, password))
{
var user = await UserManager.FindByNameAsync(userName);
if (user == null)
{
if (externalLoginProvider is IExternalLoginProviderWithPassword externalLoginProviderWithPassword)
{
user = await externalLoginProviderWithPassword.CreateUserAsync(userName, externalLoginProviderInfo.Name, password);
}
else
{
user = await externalLoginProvider.CreateUserAsync(userName, externalLoginProviderInfo.Name);
}
}
else
{
if (externalLoginProvider is IExternalLoginProviderWithPassword externalLoginProviderWithPassword)
{
await externalLoginProviderWithPassword.UpdateUserAsync(user, externalLoginProviderInfo.Name, password);
}
else
{
await externalLoginProvider.UpdateUserAsync(user, externalLoginProviderInfo.Name);
}
}
return await SignInOrTwoFactorAsync(user, isPersistent);

Considering from ExternalLoginProviderBase.GetUserInfoAsync(string userName) added to the IExternalLoginProvider, in order to solve this problem?

Describe the solution you'd like

public interface IExternalLoginProvider
{
    /// <summary>
    /// Used to try authenticate a user by this source.
    /// </summary>
    /// <param name="userName">User name or email address</param>
    /// <param name="plainPassword">Plain password of the user</param>
    /// <returns>True, indicates that this used has authenticated by this source</returns>
    Task<bool> TryAuthenticateAsync(string userName, string plainPassword);

    /// <summary>
    /// Get external user info by user name.
    /// </summary>
    /// <param name="userName">User name or email address</param>
    /// <returns>Returns user information for this user at this authentication source</returns>
    Task<ExternalLoginUserInfo> GetUserInfoAsync(string userName);

    /// <summary>
    /// This method is called when a user is authenticated by this source but the user does not exists yet.
    /// So, the source should create the user and fill the properties.
    /// </summary>
    /// <param name="userName">User name</param>
    /// <param name="providerName">The name of this provider</param>
    /// <returns>Newly created user</returns>
    Task<IdentityUser> CreateUserAsync(string userName, string providerName);

    /// <summary>
    /// This method is called after an existing user is authenticated by this source.
    /// It can be used to update some properties of the user by the source.
    /// </summary>
    /// <param name="providerName">The name of this provider</param>
    /// <param name="user">The user that can be updated</param>
    Task UpdateUserAsync(IdentityUser user, string providerName);

    /// <summary>
    /// Return a value indicating whether this source is enabled.
    /// </summary>
    /// <returns></returns>
    Task<bool> IsEnabledAsync();
}
public class ExternalLoginUserInfo
{
    [NotNull]
    public string UserName { get; private set; }

    [CanBeNull]
    public string Name { get; set; }

    [CanBeNull]
    public string Surname { get; set; }

    [CanBeNull]
    public string PhoneNumber { get; set; }

    [NotNull]
    public string Email { get; private set; }

    [CanBeNull]
    public bool? PhoneNumberConfirmed { get; set; }

    [CanBeNull]
    public bool? EmailConfirmed { get; set; }

    [CanBeNull]
    public bool? TwoFactorEnabled { get; set; }

    [CanBeNull]
    public string ProviderKey { get; set; }

    public ExternalLoginUserInfo([NotNull] string userName, [NotNull] string email)
    {
        UserName = Check.NotNullOrWhiteSpace(userName, nameof(userName));
        Email = Check.NotNullOrWhiteSpace(email, nameof(email));
    }
}
public async override Task<SignInResult> PasswordSignInAsync(
    string userName,
    string password,
    bool isPersistent,
    bool lockoutOnFailure)
{
    foreach (var externalLoginProviderInfo in AbpOptions.ExternalLoginProviders.Values)
    {
        var externalLoginProvider = (IExternalLoginProvider)Context.RequestServices
            .GetRequiredService(externalLoginProviderInfo.Type);

        if (await externalLoginProvider.TryAuthenticateAsync(userName, password))
        {
            var externalUser = await externalLoginProvider.GetUserInfoAsync(userName);
            var user = await UserManager.FindByNameAsync(externalUser.UserName);
            if (user == null)
            {
                if (externalLoginProvider is IExternalLoginProviderWithPassword externalLoginProviderWithPassword)
                {
                    user = await externalLoginProviderWithPassword.CreateUserAsync(userName, externalLoginProviderInfo.Name, password);
                }
                else
                {
                    user = await externalLoginProvider.CreateUserAsync(userName, externalLoginProviderInfo.Name);
                }
            }
            else
            {
                if (externalLoginProvider is IExternalLoginProviderWithPassword externalLoginProviderWithPassword)
                {
                    await externalLoginProviderWithPassword.UpdateUserAsync(user, externalLoginProviderInfo.Name, password);
                }
                else
                {
                    await externalLoginProvider.UpdateUserAsync(user, externalLoginProviderInfo.Name);
                }
            }

            return await SignInOrTwoFactorAsync(user, isPersistent);
        }
    }

    return await base.PasswordSignInAsync(userName, password, isPersistent, lockoutOnFailure);
}

Other related modules

if (await externalLoginProvider.TryAuthenticateAsync(request.Username, request.Password))
{
user = await UserManager.FindByNameAsync(request.Username);
if (user == null)
{
user = await externalLoginProvider.CreateUserAsync(request.Username, externalLoginProviderInfo.Name);
}
else
{
await externalLoginProvider.UpdateUserAsync(user, externalLoginProviderInfo.Name);
}
return await SetSuccessResultAsync(request, user);

if (await externalLoginProvider.TryAuthenticateAsync(context.UserName, context.Password))
{
user = await UserManager.FindByNameAsync(context.UserName);
if (user == null)
{
user = await externalLoginProvider.CreateUserAsync(context.UserName, externalLoginProviderInfo.Name);
}
else
{
await externalLoginProvider.UpdateUserAsync(user, externalLoginProviderInfo.Name);
}
await SetSuccessResultAsync(context, user);
return;

Additional context

No response

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant