fix switch club:

Problem: RefreshSignInAsync in UserService.SwitchClubAsync (Zeile 719) setzte zwar den neuen Cookie, aber HttpClient.PostAsJsonAsync empfing diesen Cookie nur intern - der Browser bekam ihn nie.

  Lösung: Form-POST statt HttpClient-API-Call, wie bei Login/Logout.

  Änderungen:

  1. ClubSwitcher.razor - Komplett überarbeitet:
    - HttpClient durch natives <form method="post"> ersetzt
    - AntiForgery-Token manuell gesetzt (wie LogoutButton)
    - Kein JavaScript/Client-Code mehr nötig
  2. AuthController.cs (Zeile 146):
    - [FromBody] → [FromForm]
    - [ValidateAntiForgeryToken] aktiviert

  Ablauf jetzt:
  1. User klickt auf Club im Dropdown
  2. Form-POST an /auth/switch-club
  3. Controller ruft SwitchClubAsync → DB-Update + RefreshSignInAsync
  4. LocalRedirect("/dashboard") → Browser erhält neuen Cookie direkt
  5. Claims sind beim Reload korrekt
This commit is contained in:
beo3000 2026-01-02 23:07:48 +01:00
parent 3b65f9f1cd
commit 39d4629e72
2 changed files with 29 additions and 72 deletions

View File

@ -1,16 +1,10 @@
@using System.Net
@using Fluxor
@using Koogle.Application.DTOs
@using Koogle.Web.Store.AuthState
@using Koogle.Application.Interfaces
@using Microsoft.AspNetCore.Antiforgery
@inject IState<AuthState> AuthState
@inject NavigationManager NavigationManager
@inject IUserService UserService
@inject HttpClient HttpClient;
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery
@inject IAntiforgery Antiforgery
@inject IHttpContextAccessor HttpContextAccessor
@inject IDispatcher Dispatcher
@inherits Fluxor.Blazor.Web.Components.FluxorComponent
@ -27,14 +21,24 @@
<ChildContent>
@foreach (var club in AuthState.Value.AvailableClubs)
{
<MudMenuItem OnClick="@(() => SwitchClubAsync(club.ClubId))"
Disabled="@(club.ClubId == AuthState.Value.CurrentClub?.ClubId)">
@if (club.ClubId == AuthState.Value.CurrentClub?.ClubId)
{
@if (club.ClubId == AuthState.Value.CurrentClub?.ClubId)
{
<MudMenuItem Disabled="true">
<MudIcon Icon="@Icons.Material.Filled.Check" Size="Size.Small" Class="mr-2"/>
}
@club.ClubName
</MudMenuItem>
@club.ClubName
</MudMenuItem>
}
else
{
<form method="post" action="/auth/switch-club">
<input type="hidden" name="__RequestVerificationToken" value="@_token" />
<input type="hidden" name="clubId" value="@club.ClubId" />
<input type="hidden" name="userProfileId" value="@AuthState.Value.CurrentUser?.ProfileId" />
<button type="submit" class="mud-menu-item mud-ripple" style="width:100%; text-align:left; background:none; border:none; cursor:pointer;">
@club.ClubName
</button>
</form>
}
}
</ChildContent>
</MudMenu>
@ -53,64 +57,17 @@ else if (AuthState.Value.IsAuthenticated && AuthState.Value.HasNoClub)
}
@code {
private string _antiToken;
private string _token = string.Empty;
protected override void OnAfterRender(bool firstRender)
protected override void OnInitialized()
{
if (firstRender)
base.OnInitialized();
var http = HttpContextAccessor.HttpContext;
if (http != null)
{
var http = HttpContextAccessor.HttpContext!;
var tokens = Antiforgery.GetAndStoreTokens(http);
_antiToken = tokens.RequestToken!;
_token = tokens?.RequestToken ?? string.Empty;
}
}
private async Task SwitchClubAsync(Guid clubId)
{
if (AuthState.Value.CurrentUser == null)
return;
var model = new SwitchClubFormDto()
{
ClubId = clubId,
UserProfileId = AuthState.Value.CurrentUser.ProfileId
};
try
{
HttpClient.DefaultRequestHeaders.Remove("RequestVerificationToken");
HttpClient.DefaultRequestHeaders.Add(
"RequestVerificationToken",
_antiToken
);
var basepath = NavigationManager.BaseUri;
var url = $"{basepath}auth/switch-club";
await HttpClient.PostAsJsonAsync(url, model);
// Dispatcher.Dispatch(new AuthState.InitializeAuthSuccessAction(model.UserProfileId, model.ClubId, roles));
NavigationManager.NavigateTo("/dashboard", forceLoad: true);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
// try
// {
// var success = await UserService.SwitchClubAsync(AuthState.Value.CurrentUser.ProfileId, clubId);
// if (success)
// {
// // Force page reload to refresh claims
// NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
// }
// }
// catch (Exception ex)
// {
// Console.WriteLine($"Club switch failed: {ex.Message}");
// }
}
}

View File

@ -142,11 +142,11 @@ namespace Koogle.Web.Controllers
/// Handles switch club.
/// </summary>
[HttpPost("switch-club")]
//[ValidateAntiForgeryToken]
public async Task<IActionResult> SwitchClub([FromBody] SwitchClubFormDto input)
[ValidateAntiForgeryToken]
public async Task<IActionResult> SwitchClub([FromForm] SwitchClubFormDto input)
{
await _userService.SwitchClubAsync(input.UserProfileId, input.ClubId);
return LocalRedirect($"/dashboard");
return LocalRedirect("/dashboard");
}
}