fix: login muito tempo parado e mais logs do stripe
All checks were successful
BCards Deployment Pipeline / Run Tests (push) Successful in 2s
BCards Deployment Pipeline / PR Validation (push) Has been skipped
BCards Deployment Pipeline / Build and Push Image (push) Successful in 15m25s
BCards Deployment Pipeline / Deploy to Production (ARM - OCI) (push) Successful in 1m17s
BCards Deployment Pipeline / Deploy to Staging (x86 - Local) (push) Has been skipped
BCards Deployment Pipeline / Cleanup Old Resources (push) Has been skipped
BCards Deployment Pipeline / Deployment Summary (push) Successful in 0s
All checks were successful
BCards Deployment Pipeline / Run Tests (push) Successful in 2s
BCards Deployment Pipeline / PR Validation (push) Has been skipped
BCards Deployment Pipeline / Build and Push Image (push) Successful in 15m25s
BCards Deployment Pipeline / Deploy to Production (ARM - OCI) (push) Successful in 1m17s
BCards Deployment Pipeline / Deploy to Staging (x86 - Local) (push) Has been skipped
BCards Deployment Pipeline / Cleanup Old Resources (push) Has been skipped
BCards Deployment Pipeline / Deployment Summary (push) Successful in 0s
This commit is contained in:
parent
572f1ebf2e
commit
406c298afb
@ -52,7 +52,7 @@ public class AuthController : Controller
|
|||||||
var result = await HttpContext.AuthenticateAsync(GoogleDefaults.AuthenticationScheme);
|
var result = await HttpContext.AuthenticateAsync(GoogleDefaults.AuthenticationScheme);
|
||||||
if (!result.Succeeded)
|
if (!result.Succeeded)
|
||||||
{
|
{
|
||||||
TempData["Error"] = "Falha na autenticação com Google";
|
TempData["Error"] = "Falha na autentica<EFBFBD><EFBFBD>o com Google";
|
||||||
return RedirectToAction("Login");
|
return RedirectToAction("Login");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ public class AuthController : Controller
|
|||||||
var result = await HttpContext.AuthenticateAsync(MicrosoftAccountDefaults.AuthenticationScheme);
|
var result = await HttpContext.AuthenticateAsync(MicrosoftAccountDefaults.AuthenticationScheme);
|
||||||
if (!result.Succeeded)
|
if (!result.Succeeded)
|
||||||
{
|
{
|
||||||
TempData["Error"] = "Falha na autenticação com Microsoft";
|
TempData["Error"] = "Falha na autentica<EFBFBD><EFBFBD>o com Microsoft";
|
||||||
return RedirectToAction("Login");
|
return RedirectToAction("Login");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,30 +105,15 @@ public class AuthController : Controller
|
|||||||
return RedirectToLocal(returnUrl);
|
return RedirectToLocal(returnUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpPost]
|
||||||
[Route("Logout")]
|
[Route("Logout")]
|
||||||
[Authorize]
|
[Authorize]
|
||||||
|
[ValidateAntiForgeryToken]
|
||||||
public async Task<IActionResult> Logout()
|
public async Task<IActionResult> 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);
|
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||||
|
|
||||||
TempData["Success"] = "Logout realizado com sucesso";
|
TempData["Success"] = "Você saiu com segurança.";
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return RedirectToAction("Index", "Home");
|
return RedirectToAction("Index", "Home");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,12 +34,14 @@ public class StripeWebhookController : ControllerBase
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync();
|
var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync();
|
||||||
|
_logger.LogInformation($"Recebido:{json}");
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(_webhookSecret))
|
if (string.IsNullOrEmpty(_webhookSecret))
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Webhook secret not configured");
|
_logger.LogWarning("Webhook secret not configured");
|
||||||
return BadRequest("Webhook secret not configured");
|
return BadRequest("Webhook secret not configured");
|
||||||
}
|
}
|
||||||
|
_logger.LogWarning($"Recebido:{json}");
|
||||||
|
|
||||||
var stripeSignature = Request.Headers["Stripe-Signature"].FirstOrDefault();
|
var stripeSignature = Request.Headers["Stripe-Signature"].FirstOrDefault();
|
||||||
if (string.IsNullOrEmpty(stripeSignature))
|
if (string.IsNullOrEmpty(stripeSignature))
|
||||||
|
|||||||
@ -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<OAuthCorrelationErrorHandlerMiddleware> _logger;
|
||||||
|
|
||||||
|
public OAuthCorrelationErrorHandlerMiddleware(RequestDelegate next, ILogger<OAuthCorrelationErrorHandlerMiddleware> 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -173,28 +173,50 @@ builder.Services.AddAuthentication(options =>
|
|||||||
{
|
{
|
||||||
options.LoginPath = "/Auth/Login";
|
options.LoginPath = "/Auth/Login";
|
||||||
options.LogoutPath = "/Auth/Logout";
|
options.LogoutPath = "/Auth/Logout";
|
||||||
// 🔥 OTIMIZAÇÃO: Timeout de sessão estendido para 8h
|
|
||||||
options.ExpireTimeSpan = TimeSpan.FromHours(8);
|
options.ExpireTimeSpan = TimeSpan.FromHours(8);
|
||||||
options.SlidingExpiration = true;
|
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 =>
|
.AddGoogle(options =>
|
||||||
{
|
{
|
||||||
var googleAuth = builder.Configuration.GetSection("Authentication:Google");
|
var googleAuth = builder.Configuration.GetSection("Authentication:Google");
|
||||||
options.ClientId = googleAuth["ClientId"] ?? "";
|
options.ClientId = googleAuth["ClientId"] ?? "";
|
||||||
options.ClientSecret = googleAuth["ClientSecret"] ?? "";
|
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<ILogger<Program>>();
|
||||||
|
logger.LogWarning("Google remote failure: {Failure}", context.Failure?.Message);
|
||||||
|
|
||||||
|
context.Response.Redirect("/Auth/Login?error=remote_failure");
|
||||||
|
context.HandleResponse();
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
};
|
||||||
})
|
})
|
||||||
.AddMicrosoftAccount(options =>
|
.AddMicrosoftAccount(options =>
|
||||||
{
|
{
|
||||||
var msAuth = builder.Configuration.GetSection("Authentication:Microsoft");
|
var msAuth = builder.Configuration.GetSection("Authentication:Microsoft");
|
||||||
options.ClientId = msAuth["ClientId"] ?? "";
|
options.ClientId = msAuth["ClientId"] ?? "";
|
||||||
options.ClientSecret = msAuth["ClientSecret"] ?? "";
|
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
|
// Força seleção de conta a cada login
|
||||||
options.AuthorizationEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
|
options.AuthorizationEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
|
||||||
options.TokenEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
|
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
|
options.Events = new OAuthEvents
|
||||||
{
|
{
|
||||||
OnRedirectToAuthorizationEndpoint = context =>
|
OnRedirectToAuthorizationEndpoint = context =>
|
||||||
@ -233,6 +255,15 @@ builder.Services.AddAuthentication(options =>
|
|||||||
|
|
||||||
context.Response.Redirect(redirectUri);
|
context.Response.Redirect(redirectUri);
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
},
|
||||||
|
OnRemoteFailure = context =>
|
||||||
|
{
|
||||||
|
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<Program>>();
|
||||||
|
logger.LogWarning("Microsoft remote failure: {Failure}", context.Failure?.Message);
|
||||||
|
|
||||||
|
context.Response.Redirect("/Auth/Login?error=remote_failure");
|
||||||
|
context.HandleResponse();
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@ -15,6 +15,24 @@
|
|||||||
<p class="text-muted">Entre na sua conta</p>
|
<p class="text-muted">Entre na sua conta</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@if (Context.Request.Query.ContainsKey("error"))
|
||||||
|
{
|
||||||
|
<div class="alert alert-warning text-center mb-4" role="alert">
|
||||||
|
@switch (Context.Request.Query["error"].ToString())
|
||||||
|
{
|
||||||
|
case "session_expired":
|
||||||
|
<text>Sua sessão expirou. Por favor, faça login novamente.</text>
|
||||||
|
break;
|
||||||
|
case "remote_failure":
|
||||||
|
<text>Ocorreu um erro durante a autenticação com o provedor. Tente novamente.</text>
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
<text>Ocorreu um erro de autenticação. Tente novamente.</text>
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
<form asp-controller="Auth" asp-action="LoginWithGoogle" method="post" class="mb-3">
|
<form asp-controller="Auth" asp-action="LoginWithGoogle" method="post" class="mb-3">
|
||||||
@if (!string.IsNullOrEmpty(returnUrl))
|
@if (!string.IsNullOrEmpty(returnUrl))
|
||||||
{
|
{
|
||||||
|
|||||||
@ -170,10 +170,12 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link @(ViewBag.IsHomePage == true ? "text-white" : "text-dark")"
|
<form asp-area="" asp-controller="Auth" asp-action="Logout" method="post" id="logoutForm" class="d-inline">
|
||||||
asp-area="" asp-controller="Auth" asp-action="Logout">
|
@Html.AntiForgeryToken()
|
||||||
<i class="fas fa-sign-out-alt me-1"></i>Sair
|
<a href="#" onclick="document.getElementById('logoutForm').submit(); return false;" class="nav-link @(ViewBag.IsHomePage == true ? "text-white" : "text-dark")">
|
||||||
</a>
|
<i class="fas fa-sign-out-alt me-1"></i>Sair
|
||||||
|
</a>
|
||||||
|
</form>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user