abpframework / abp

Open-source web application framework for ASP.NET Core! Offers an opinionated architecture to build enterprise software solutions with best practices on top of the .NET. Provides the fundamental infrastructure, cross-cutting-concern implementations, startup templates, application modules, UI themes, tooling and documentation.
https://abp.io
GNU Lesser General Public License v3.0
12.99k stars 3.46k forks source link

UserName should be unique. #20418

Open Kenjiang110 opened 3 months ago

Kenjiang110 commented 3 months ago

Is there an existing issue for this?

Description

You can use IdentityUserManager to create two users have same username and email.

Reproduction Steps

var userName = "test"; var email = "test@test.com"; var user = new IdentityUser(GuidGenerator.Create(), userName, email, CurrentTenant.Id); await UserManager.CreateAsync(user); user = new IdentityUser(GuidGenerator.Create(), userName, email, CurrentTenant.Id); await UserManager.CreateAsync(user);

Expected behavior

Second "UserManager.CreateAsync(user)" should throw an exception becasue of duplicated userName.

Actual behavior

Two users with same userName and email have been created.

Regression?

No response

Known Workarounds

No response

Version

8.2.0

User Interface

Common (Default)

Database Provider

EF Core (Default)

Tiered or separate authentication server

None (Default)

Operation System

Windows (Default)

Other information

No response

maliming commented 3 months ago

hi

You can try to call the SaveChangesAsync(commit the transaction)

var userName = "test";
var email = "[test@test.com](mailto:test@test.com)";

var user = new IdentityUser(GuidGenerator.Create(), userName, email, CurrentTenant.Id);
await UserManager.CreateAsync(user);

await unitOfWorkManager.Current.SaveChangesAsync();

user = new IdentityUser(GuidGenerator.Create(), userName, email, CurrentTenant.Id);
await UserManager.CreateAsync(user);

await unitOfWorkManager.Current.SaveChangesAsync();
Kenjiang110 commented 3 months ago

The code I provided is just to reproduce the problem. Sorry for the confusion. My real scenario is calling the method below from a client, so the UnitOfWork will commit automatically?

[UnitOfWork] protected virtual async Task CreateWeChatUserAsync(ExternalLoginInfo info) { //user var userName = $"wx_{info.ProviderKey}"; var user = await UserManager.FindByNameAsync(userName); if (user == null) { var email = @.***"; user = new IdentityUser(GuidGenerator.Create(), userName, email, CurrentTenant.Id) { Name = info.Principal.GetClaim(WeChatClaimTypes.NickName) }; info.AuthenticationTokens?.ForEach(token => user.SetToken(info.LoginProvider, token.Name, token.Value)); user.AddClaims(GuidGenerator, info.Principal.Claims); if (info.Principal.GetClaim(WeChatClaimTypes.Country).IsNullOrEmpty()) { user.AddClaim(GuidGenerator, new Claim(WeChatClaimTypes.Country, BobAbpConsts.ChinaCountryCode)); //default country } CheckIdentityErrors(await UserManager.CreateAsync(user)); CheckIdentityErrors(await UserManager.AddDefaultRolesAsync(user)); } //External login if (await UserManager.FindByLoginAsync(info.LoginProvider, info.ProviderKey) == null) { CheckIdentityErrors(await UserManager.AddLoginAsync(user, info)); }

return user;

}

maliming commented 3 months ago

Please share steps and code to reproduce.

Kenjiang110 commented 3 months ago

1)Create a new solution using "MYSQL": abp new Acme.BookStore -dbms MySQL -m none --theme leptonx-lite -csf

2)Add IDemoAppService.cs to project Application.Contracts: public interface IDemoAppService: IApplicationService { Task CreateUserAsync(); }

3)Add DemoAppService.cs to project Application: namespace Acme.BookStore { public class DemoAppService : BookStoreAppService, IDemoAppService { protected IdentityUserManager UserManager => LazyServiceProvider.LazyGetRequiredService();

    [UnitOfWork]
    public async Task CreateUserAsync()
    {
        var userName = $"wx_01";
        var user = await UserManager.FindByNameAsync(userName);
        if (user == null)
        {
            var email = ***@***.***";
            user = new IdentityUser(GuidGenerator.Create(), userName, email, CurrentTenant.Id)
            {
                Name = userName
            };
            await UserManager.CreateAsync(user);
        }
    }
}

} 4)Add button "Demo" to Pages/Index.cshtml @if (!CurrentUser.IsAuthenticated) { @L["Login"] } else {

    }

5) Edit Pages/index.js, add click handler to button "Demo". $(function () { abp.log.debug('Index.js initialized!');

$("#demo").click(function () {
    acme.bookStore.demo.createUser(); 
    acme.bookStore.demo.createUser();
});

}); 6)Run project Web, login, click the button "Demo". 7)Goto page "Users"

@.***

From: maliming Date: 2024-08-07 16:06 To: abpframework/abp CC: Kenjiang110; Author Subject: Re: [abpframework/abp] UserName should be unique. (Issue #20418) Please share steps and code to reproduce. — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.Message ID: @.***>

Pantex9 commented 3 months ago

Hi, do you know if this issue is still open?

Kenjiang110 commented 3 months ago

It still looks open, but I don't think it will be handled because the bug is almost impossible to trigger under normal circumstances.

@.***

From: Milos Pantelic Date: 2024-08-27 07:07 To: abpframework/abp CC: Kenjiang110; Author Subject: Re: [abpframework/abp] UserName should be unique. (Issue #20418) Hi, do you know if this issue is still open? — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.Message ID: @.***>