You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 8 MVC中Google身份验证实现失败,报DuplicateUserName错误

.NET 8 MVC + SQLite第三方登录问题:AddLoginAsync始终返回"DuplicateUserName"错误

我正在学习.NET中的第三方登录功能,基于.NET 8 MVC和SQLite数据库搭建了测试应用。目前除了await _userManager.AddLoginAsync(identityUser, extLoginInfo)这一步外,其他功能均正常,但该方法始终返回**"DuplicateUserName"错误,错误描述为"Username xxx@gmail.com is already taken"**。

我实现了ExternalLogin和ExternalLoginCallBack两个Action方法,问题出在后者,调试时的QuickWatch窗口已高亮显示该错误。

重要说明:控制器中的方法实际调用的是仓储层实现的SignInManager和UserManager,截图中第103行断点处的方法本质是:

_userManager.AddLoginAsync(identityUser, extLoginInfo)

场景复现

  • 场景1:使用应用注册页面已注册的用户(已存入AspNetUsers表),通过Google登录时,无法在AspNetUserLogin表中创建关联记录,报相同错误。
  • 场景2:使用未在AspNetUsers表中注册的新Gmail账号直接通过Google登录,新用户能成功添加到AspNetUsers表,但依然无法在AspNetUserLogin表中创建记录,同样报"DuplicateUserName"错误。

补充说明

  1. 需求:支持Google/Facebook/Twitter登录,三个提供商均存在相同问题。要求:不允许同一第三方账号绑定多个本地账号;未注册用户通过社交账号登录时,需将信息同时存入AspNetUsers和AspNetUserLogin表(AspNetUsers的UserId作为AspNetUserLogin的外键)。
  2. 测试情况:测试时AspNetUsers表为空,直接使用社交账号登录,仍出现该错误。
  3. 配置信息:

Program.cs相关配置

// google authentication
var clientId = Environment.GetEnvironmentVariable("GoogleClientId");
var clientSecret = Environment.GetEnvironmentVariable("GoogleClientSecret");

builder.Services.AddAuthentication()
                .AddGoogle(options =>
{
    options.ClientId = clientId;
    options.ClientSecret = clientSecret;
}).AddFacebook(fboptions =>
{
    fboptions.AppId = builder.Configuration["Auth:Facebook:AppId"].ToString(); ;
    fboptions.AppSecret = builder.Configuration["Auth:Facebook:AppSecret"].ToString();
}).AddTwitter(twitter =>
{
    twitter.ConsumerKey = builder.Configuration["Auth:Twitter:ConsumerKey"];
    twitter.ConsumerSecret = builder.Configuration["Auth:Twitter:ConsumerSecret"];
});

builder.Services.AddScoped<IReadFileService, ReadFileService>();
builder.Services.AddScoped<IFileReadRepo, FileReadRepo>();
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddScoped<IUserRepository, UserRepository>();
builder.Services.AddScoped<IRoleService, RoleService>();
builder.Services.AddScoped<IRoleRepository, RoleRepository>();
builder.Services.AddScoped<IExternalLoginProviderService, ExternalLoginProviderService>();
builder.Services.AddScoped<IExternalLoginProviderRepository, ExternalLoginProviderRepository>();

var app = builder.Build();

appsettings.json相关配置

"Auth": {
  "Facebook": {
    "AppId": "xxxxxxxxxx",
    "AppSecret": "xxxxxxxxx"
  },
  "Twitter": {
    "ConsumerKey": "yyyyyyyyyyyyyy",
    "ConsumerSecret": "yyyyyyyyyyyyyy"
  }
}
  1. 相关控制器代码:
[AllowAnonymous]
[HttpPost]
public IActionResult ExternalLogin(string provider, string returnUrl)
{
    var redirectUrl = Url.Action("ExternalLoginCallBack", "Login", new { ReturnUrl = returnUrl });

    var authProperties = _externalLoginProviderService.ConfigureExternalAuthenticationProps(provider, redirectUrl);
    
    
    return new ChallengeResult(provider, authProperties);                     
}


[AllowAnonymous]        
public async Task<IActionResult> ExternalLoginCallBack(string returnUrl = null, string remoteError = null)
{
    if(string.IsNullOrEmpty(returnUrl)) 
    {
        returnUrl = Url.Content("~/");
    }

    var loginViewModel = new LoginViewModel
    {
        ReturnUrl = returnUrl,
        ExternalLoginProviders = await _externalLoginProviderService.GetExternalLoginProviders(),
    };

    if(!string.IsNullOrWhiteSpace(remoteError)) 
    {
        ModelState.AddModelError("Errors during login : ", remoteError);
        
        return View("Login", loginViewModel);
    }
    
    var loginInfo = await _externalLoginProviderService.GetExternalLoginInfo();

    if (loginInfo == null)
    {
        ModelState.AddModelError("", $"Error loading information from external login provider");
        return View("Login", loginViewModel);
    }

    var signInResult = await _externalLoginProviderService.SignInUsingExternalLogin(
                                        loginInfo.ProviderDisplayName, loginInfo.ProviderKey, false, false);

    if (signInResult.Succeeded)
    {
        return string.IsNullOrWhiteSpace(returnUrl) ? RedirectToAction("MyProfile", "User") : LocalRedirect(returnUrl);
    }
    else
    {
        var claimFromExternal = loginInfo.Principal.FindFirstValue(ClaimTypes.Email) ??  // Google or Facebook
                                loginInfo.Principal.FindFirstValue(ClaimTypes.Name); // Twitter
        
        if (claimFromExternal != null) 
        {
            var user = await _userService.GetUserByEmail(claimFromExternal);                    
            
            if (user == null) 
            {                                              
               await _userService.CreateExternalUserInLocal(claimFromExternal);                                             
            }

            var userLoginInfo = new UserLoginInfo(loginInfo.LoginProvider, loginInfo.ProviderKey, loginInfo.ProviderDisplayName);
            
            var identityUser = new IdentityUser
            {
                UserName = claimFromExternal,
                Email = claimFromExternal                        
            };
            
            var result = await _userService.AddExternalLoginUser(identityUser, userLoginInfo);
            await _userService.SignInExternalUser(identityUser);

            return string.IsNullOrWhiteSpace(returnUrl) ? RedirectToAction("MyProfile", "User") : LocalRedirect(returnUrl); 
        }
    }

    return View("Login", loginViewModel);
}

内容的提问来源于stack exchange,提问作者Abhishek Jadhav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 10:46:04