From 406c298afbf9a33ed9c7bcd1e5a74699d2c32c5f Mon Sep 17 00:00:00 2001 From: Ricardo Carneiro Date: Sun, 31 Aug 2025 20:21:56 -0300 Subject: [PATCH] fix: login muito tempo parado e mais logs do stripe --- src/BCards.Web/Controllers/AuthController.cs | 29 ++++---------- .../Controllers/StripeWebhookController.cs | 4 +- .../OAuthCorrelationErrorHandlerMiddleware.cs | 39 +++++++++++++++++++ src/BCards.Web/Program.cs | 37 ++++++++++++++++-- src/BCards.Web/Views/Auth/Login.cshtml | 18 +++++++++ src/BCards.Web/Views/Shared/_Layout.cshtml | 10 +++-- 6 files changed, 107 insertions(+), 30 deletions(-) create mode 100644 src/BCards.Web/Middleware/OAuthCorrelationErrorHandlerMiddleware.cs diff --git a/src/BCards.Web/Controllers/AuthController.cs b/src/BCards.Web/Controllers/AuthController.cs index 7a48beb..c92485e 100644 --- a/src/BCards.Web/Controllers/AuthController.cs +++ b/src/BCards.Web/Controllers/AuthController.cs @@ -52,7 +52,7 @@ public class AuthController : Controller var result = await HttpContext.AuthenticateAsync(GoogleDefaults.AuthenticationScheme); if (!result.Succeeded) { - TempData["Error"] = "Falha na autenticaēćo com Google"; + TempData["Error"] = "Falha na autentica��o com Google"; return RedirectToAction("Login"); } @@ -82,7 +82,7 @@ public class AuthController : Controller var result = await HttpContext.AuthenticateAsync(MicrosoftAccountDefaults.AuthenticationScheme); if (!result.Succeeded) { - TempData["Error"] = "Falha na autenticaēćo com Microsoft"; + TempData["Error"] = "Falha na autentica��o com Microsoft"; return RedirectToAction("Login"); } @@ -105,31 +105,16 @@ public class AuthController : Controller return RedirectToLocal(returnUrl); } - [HttpGet] + [HttpPost] [Route("Logout")] [Authorize] + [ValidateAntiForgeryToken] public async Task Logout() { - // Identifica qual provedor foi usado - var authResult = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme); - var loginProvider = authResult.Principal?.FindFirst("LoginProvider")?.Value; - - // Faz logout local primeiro await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); - - TempData["Success"] = "Logout realizado com sucesso"; - - // Se foi Microsoft, faz logout completo no provedor - if (loginProvider == "Microsoft") - { - return SignOut(MicrosoftAccountDefaults.AuthenticationScheme); - } - // Se foi Google, faz logout completo no provedor - else if (loginProvider == "Google") - { - return SignOut(GoogleDefaults.AuthenticationScheme); - } - + + TempData["Success"] = "VocĆŖ saiu com seguranƧa."; + return RedirectToAction("Index", "Home"); } diff --git a/src/BCards.Web/Controllers/StripeWebhookController.cs b/src/BCards.Web/Controllers/StripeWebhookController.cs index b69db47..4464e8a 100644 --- a/src/BCards.Web/Controllers/StripeWebhookController.cs +++ b/src/BCards.Web/Controllers/StripeWebhookController.cs @@ -34,12 +34,14 @@ public class StripeWebhookController : ControllerBase try { var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync(); - + _logger.LogInformation($"Recebido:{json}"); + if (string.IsNullOrEmpty(_webhookSecret)) { _logger.LogWarning("Webhook secret not configured"); return BadRequest("Webhook secret not configured"); } + _logger.LogWarning($"Recebido:{json}"); var stripeSignature = Request.Headers["Stripe-Signature"].FirstOrDefault(); if (string.IsNullOrEmpty(stripeSignature)) diff --git a/src/BCards.Web/Middleware/OAuthCorrelationErrorHandlerMiddleware.cs b/src/BCards.Web/Middleware/OAuthCorrelationErrorHandlerMiddleware.cs new file mode 100644 index 0000000..2f250aa --- /dev/null +++ b/src/BCards.Web/Middleware/OAuthCorrelationErrorHandlerMiddleware.cs @@ -0,0 +1,39 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Microsoft.AspNetCore.Authentication.Cookies; + +namespace BCards.Web.Middleware +{ + public class OAuthCorrelationErrorHandlerMiddleware + { + private readonly RequestDelegate _next; + private readonly ILogger _logger; + + public OAuthCorrelationErrorHandlerMiddleware(RequestDelegate next, ILogger logger) + { + _next = next; + _logger = logger; + } + + public async Task InvokeAsync(HttpContext context) + { + try + { + await _next(context); + } + catch (AuthenticationFailureException ex) + when (ex.Message.Contains("Correlation failed")) + { + _logger.LogWarning(ex, "OAuth correlation failure detected for trace id {TraceId}. This often happens when the user's session expires on the login page before they complete the OAuth flow. Cleaning up and redirecting to login.", context.TraceIdentifier); + + // Clean up the failed authentication attempt + await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + + // Redirect to a clean login page with an error message + context.Response.Redirect("/Auth/Login?error=session_expired"); + } + } + } +} diff --git a/src/BCards.Web/Program.cs b/src/BCards.Web/Program.cs index 5f4f21c..cea0c52 100644 --- a/src/BCards.Web/Program.cs +++ b/src/BCards.Web/Program.cs @@ -173,28 +173,50 @@ builder.Services.AddAuthentication(options => { options.LoginPath = "/Auth/Login"; options.LogoutPath = "/Auth/Logout"; - // šŸ”„ OTIMIZAƇƃO: Timeout de sessĆ£o estendido para 8h options.ExpireTimeSpan = TimeSpan.FromHours(8); options.SlidingExpiration = true; + + // šŸ”„ CORREƇƃO: ConfiguraƧƵes de cookie seguras para evitar problemas de correlação + options.Cookie.HttpOnly = true; + options.Cookie.IsEssential = true; + options.Cookie.SameSite = SameSiteMode.Lax; // Essencial para fluxos OAuth + options.Cookie.SecurePolicy = CookieSecurePolicy.Always; // Garante HTTPS }) .AddGoogle(options => { var googleAuth = builder.Configuration.GetSection("Authentication:Google"); options.ClientId = googleAuth["ClientId"] ?? ""; options.ClientSecret = googleAuth["ClientSecret"] ?? ""; + options.CallbackPath = "/signin-google"; // Path explĆ­cito + options.BackchannelTimeout = TimeSpan.FromSeconds(30); + + // šŸ”„ CORREƇƃO: Handler para falhas remotas (ex: usuĆ”rio nega permissĆ£o) + options.Events = new OAuthEvents + { + OnRemoteFailure = context => + { + var logger = context.HttpContext.RequestServices.GetRequiredService>(); + logger.LogWarning("Google remote failure: {Failure}", context.Failure?.Message); + + context.Response.Redirect("/Auth/Login?error=remote_failure"); + context.HandleResponse(); + return Task.CompletedTask; + } + }; }) .AddMicrosoftAccount(options => { var msAuth = builder.Configuration.GetSection("Authentication:Microsoft"); options.ClientId = msAuth["ClientId"] ?? ""; options.ClientSecret = msAuth["ClientSecret"] ?? ""; - options.CallbackPath = "/signin-microsoft"; + options.CallbackPath = "/signin-microsoft"; // Path explĆ­cito + options.BackchannelTimeout = TimeSpan.FromSeconds(30); // ForƧa seleção de conta a cada login options.AuthorizationEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize"; options.TokenEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/token"; - // šŸ”„ SOLUƇƃO RADICAL: SEMPRE FORƇAR HTTPS + // šŸ”„ CORREƇƃO: Handler para falhas remotas e preservação do evento existente options.Events = new OAuthEvents { OnRedirectToAuthorizationEndpoint = context => @@ -233,6 +255,15 @@ builder.Services.AddAuthentication(options => context.Response.Redirect(redirectUri); return Task.CompletedTask; + }, + OnRemoteFailure = context => + { + var logger = context.HttpContext.RequestServices.GetRequiredService>(); + logger.LogWarning("Microsoft remote failure: {Failure}", context.Failure?.Message); + + context.Response.Redirect("/Auth/Login?error=remote_failure"); + context.HandleResponse(); + return Task.CompletedTask; } }; }); diff --git a/src/BCards.Web/Views/Auth/Login.cshtml b/src/BCards.Web/Views/Auth/Login.cshtml index 5d01978..617931a 100644 --- a/src/BCards.Web/Views/Auth/Login.cshtml +++ b/src/BCards.Web/Views/Auth/Login.cshtml @@ -15,6 +15,24 @@

Entre na sua conta

+ @if (Context.Request.Query.ContainsKey("error")) + { + + } +
@if (!string.IsNullOrEmpty(returnUrl)) { diff --git a/src/BCards.Web/Views/Shared/_Layout.cshtml b/src/BCards.Web/Views/Shared/_Layout.cshtml index 81d6395..a358780 100644 --- a/src/BCards.Web/Views/Shared/_Layout.cshtml +++ b/src/BCards.Web/Views/Shared/_Layout.cshtml @@ -170,10 +170,12 @@
} else