feat(identity): add logging and descriptive error handling for Google callback (fixes #3)

This commit is contained in:
2026-05-07 19:25:52 +02:00
parent 140cf270cc
commit 5b0590f113
2 changed files with 47 additions and 2 deletions
@@ -90,11 +90,30 @@
</div> </div>
@code { @code {
[Parameter]
[SupplyParameterFromQuery(Name = "error")]
public string? ErrorCode { get; set; }
private LoginModel _loginModel = new(); private LoginModel _loginModel = new();
private string? _errorMessage; private string? _errorMessage;
private bool _isSubmitting; private bool _isSubmitting;
private bool _showPassword; private bool _showPassword;
protected override void OnInitialized()
{
if (!string.IsNullOrEmpty(ErrorCode))
{
_errorMessage = ErrorCode switch
{
"ExternalLoginFailed" => "Nie udało się zalogować przez Google. Spróbuj ponownie.",
"ProvisioningFailed" => "Wystąpił błąd podczas przygotowywania Twojego konta.",
"UserAlreadyExists" => "Użytkownik o tym adresie e-mail już istnieje. Zaloguj się tradycyjnie hasłem.",
"LockedOut" => "Twoje konto zostało zablokowane. Spróbuj ponownie później.",
_ => "Wystąpił nieoczekiwany błąd podczas logowania."
};
}
}
private async Task HandleLogin() private async Task HandleLogin()
{ {
_isSubmitting = true; _isSubmitting = true;
+28 -2
View File
@@ -355,31 +355,57 @@ app.MapGet("/identity/login/google", (string? returnUrl) =>
app.MapGet("/identity/callback/google", async ( app.MapGet("/identity/callback/google", async (
HttpContext context, HttpContext context,
SignInManager<NexusUser> signInManager, SignInManager<NexusUser> signInManager,
UserManager<NexusUser> userManager) => UserManager<NexusUser> userManager,
ILogger<Program> logger) =>
{ {
var info = await signInManager.GetExternalLoginInfoAsync(); var info = await signInManager.GetExternalLoginInfoAsync();
if (info == null) return Results.Redirect("/account/login?error=ExternalLoginFailed"); if (info == null)
{
logger.LogWarning("External login info from Google is null.");
return Results.Redirect("/account/login?error=ExternalLoginFailed");
}
var result = await signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false); var result = await signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false);
if (result.Succeeded) if (result.Succeeded)
{ {
logger.LogInformation("User logged in via Google: {Email}", info.Principal.FindFirstValue(ClaimTypes.Email));
return Results.Redirect("/"); return Results.Redirect("/");
} }
if (result.IsLockedOut)
{
logger.LogWarning("User account locked out during Google login: {Email}", info.Principal.FindFirstValue(ClaimTypes.Email));
return Results.Redirect("/account/login?error=LockedOut");
}
// New user provisioning // New user provisioning
var email = info.Principal.FindFirstValue(ClaimTypes.Email); var email = info.Principal.FindFirstValue(ClaimTypes.Email);
if (email != null) if (email != null)
{ {
var user = new NexusUser { UserName = email, Email = email, EmailConfirmed = true }; var user = new NexusUser { UserName = email, Email = email, EmailConfirmed = true };
var createResult = await userManager.CreateAsync(user); var createResult = await userManager.CreateAsync(user);
if (createResult.Succeeded) if (createResult.Succeeded)
{ {
await userManager.AddLoginAsync(user, info); await userManager.AddLoginAsync(user, info);
await signInManager.SignInAsync(user, isPersistent: false); await signInManager.SignInAsync(user, isPersistent: false);
logger.LogInformation("New user provisioned via Google: {Email}", email);
return Results.Redirect("/"); return Results.Redirect("/");
} }
// Log specific errors
foreach (var error in createResult.Errors)
{
logger.LogError("Google provisioning failed for {Email}: {Code} - {Description}", email, error.Code, error.Description);
}
if (createResult.Errors.Any(e => e.Code == "DuplicateEmail" || e.Code == "DuplicateUserName"))
{
return Results.Redirect("/account/login?error=UserAlreadyExists");
}
} }
logger.LogError("Google provisioning failed - unknown reason for email {Email}", email);
return Results.Redirect("/account/login?error=ProvisioningFailed"); return Results.Redirect("/account/login?error=ProvisioningFailed");
}); });