Blazor WebAssembly+ASP.NET Core9 Cookie认证:LoginAsync始终返回False
问题描述
我正在使用Blazor WebAssembly和ASP.NET Core 9 Web API开发全栈应用,已从localStorage令牌管理切换为HttpOnly Cookie认证。调用客户端LoginAsync方法时,API成功返回200 OK,且accessToken Cookie已在浏览器中正确设置(通过DevTools验证),但LoginAsync始终返回False,导致UI无法更新为已认证状态。
登录页面代码
<div class="login-page"> <div class="login-box"> <div class="login-header"> <h1>Hoş Geldiniz</h1> </div> <EditForm Model="_model" OnSubmit="HandleLogin" class="login-form"> <DataAnnotationsValidator /> <ValidationSummary /> <div class="form-group"> <label>Kullanıcı Adı</label> <InputText @bind-Value="_model.UserName" class="form-control" placeholder="kullanici_adi" /> <ValidationMessage For="() => _model.UserName" /> </div> <div class="form-group"> <label>Şifre</label> <InputText type="password" @bind-Value="_model.Password" class="form-control" placeholder="••••••••" /> <ValidationMessage For="() => _model.Password" /> </div> @if (!string.IsNullOrWhiteSpace(_error)) { <div class="alert alert-danger login-error"> <i class="bi bi-exclamation-triangle-fill"></i> @_error </div> } <button type="submit" disabled="@_isBusy" class="login-button"> @if (_isBusy) { <span class="spinner"></span> } Giriş Yap </button> <div class="register-link"> Hesabınız yok mu? <a href="/create-user">Kayıt Ol</a> </div> </EditForm> </div> </div> @code { private LoginDto _model = new(); private bool _isBusy; private string? _error; private HttpClient _apiClient; protected override void OnInitialized() { _apiClient = HttpClientFactory.CreateClient("Testify.API"); } private async Task HandleLogin() { _isBusy = true; _error = null; try { var response = await _apiClient.PostAsJsonAsync("api/auth/login", _model); if (response.IsSuccessStatusCode) { NotifyAuthStateChanged(); NavigationManager.NavigateTo("/", forceLoad: true); } else { _error = await response.Content.ReadAsStringAsync(); if (string.IsNullOrWhiteSpace(_error)) { _error = "Kullanıcı adı veya şifre hatalı"; } } } catch (Exception ex) { Console.Error.WriteLine($"Login error: {ex}"); _error = "Giriş sırasında bir hata oluştu"; } finally { _isBusy = false; } } private void NotifyAuthStateChanged() { if (QuizAuthStateProvider is QuizAuthStateProvider quizAuth) { quizAuth.NotifyStateChanged(); } } }
QuizAuthStateProvider代码
public class QuizAuthStateProvider : AuthenticationStateProvider { private readonly HttpClient _httpClient; private ClaimsPrincipal _currentUser = new(new ClaimsIdentity()); public QuizAuthStateProvider(HttpClient httpClient) { _httpClient = httpClient; } public override Task<AuthenticationState> GetAuthenticationStateAsync() { return Task.FromResult(new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()))); } public async Task<bool> LoginAsync(string username, string password) { // Cookie otomatik olarak tarayıcıya set edilecek var response = await _httpClient.PostAsJsonAsync("/api/auth/login", new { username, password }); if (response.IsSuccessStatusCode) { // Sunucudan gelen cookie ile artık kimlik doğrulandı _currentUser = new ClaimsPrincipal(new ClaimsIdentity( new[] { new Claim(ClaimTypes.Name, username) }, "Cookies")); NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); return true; } return false; } public async Task LogoutAsync() { await _httpClient.PostAsync("/api/auth/logout", null); _currentUser = new ClaimsPrincipal(new ClaimsIdentity()); NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); } public void NotifyStateChanged() { NotifyAuthenticationStateChanged(GetAuthenticationStateAsync()); } }
AuthLoggingHandler代码
public class AuthLoggingHandler : DelegatingHandler { private readonly ILogger<AuthLoggingHandler> _logger; private readonly IJSRuntime _jsRuntime; // Sadece DI ile alınan parametreler, HttpMessageHandler kaldırıldı public AuthLoggingHandler(IJSRuntime jsRuntime, ILogger<AuthLoggingHandler> logger) { _jsRuntime = jsRuntime ?? throw new ArgumentNullException(nameof(jsRuntime)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } protected override async Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { _logger.LogDebug("Initiating request to {Method} {Uri}", request.Method, request.RequestUri); var response = await base.SendAsync(request, cancellationToken); _logger.LogDebug("Received {StatusCode} response from {Uri}", response.StatusCode, request.RequestUri); return response; } }
Credentials.js代码
// POST isteği, çerezlerle birlikte window.postWithCredentials = async function (url, body) { try { const response = await fetch(url, { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) }); if (!response.ok) throw new Error("HTTP " + response.status); return await response.json(); } catch (err) { console.error("postWithCredentials error:", err); throw err; } }; // Çerezleri döndürür window.getCookies = function () { return document.cookie; }; // GET isteği, çerezlerle birlikte window.getWithCredentials = async function (url) { try { const response = await fetch(url, { method: "GET", credentials: "include" }); if (!response.ok) throw new Error("HTTP " + response.status); return await response.json(); } catch (err) { console.error("getWithCredentials error:", err); throw err; } }; // Sadece giriş yapıldıysa me fonksiyonunu çağır window.callMeIfLoggedIn = async function (meUrl) { if (localStorage.getItem("isLoggedIn") === "true") { try { const user = await window.getWithCredentials(meUrl); // Kullanıcı bilgilerini işle console.log("Kullanıcı:", user); } catch (err) { // Hata yönetimi console.warn("Me endpoint hatası:", err); } } else { // Giriş yapılmamış console.log("Kullanıcı giriş yapmamış."); } };
CORS配置代码
public static void ConfigureApplicationCookie(this IServiceCollection services) { services.ConfigureApplicationCookie(options => { options.Cookie.HttpOnly = true; // HttpOnly cookie olarak ayarla options.ExpireTimeSpan = TimeSpan.FromDays(7); // 7 gün geçerli olsun options.SlidingExpiration = true; // Kaydırmalı geçerlilik süresi options.Cookie.SecurePolicy = CookieSecurePolicy.Always; // HTTPS zorunlu options.Cookie.SameSite = SameSiteMode.None; // SameSite özelliğini sıkı yap }); }
内容的提问来源于stack exchange,提问作者Mehmet
相关产品推荐
相关产品推荐

