.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"错误。
补充说明
- 需求:支持Google/Facebook/Twitter登录,三个提供商均存在相同问题。要求:不允许同一第三方账号绑定多个本地账号;未注册用户通过社交账号登录时,需将信息同时存入AspNetUsers和AspNetUserLogin表(AspNetUsers的UserId作为AspNetUserLogin的外键)。
- 测试情况:测试时AspNetUsers表为空,直接使用社交账号登录,仍出现该错误。
- 配置信息:
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" } }
- 相关控制器代码:
[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
相关产品推荐
相关产品推荐

