Laden...

Migration von Blazor WASM .NET 7 zu Blazor "Auto" .NET 8

Erstellt von TomSchmitz vor 2 Monaten Letzter Beitrag vor 2 Monaten 341 Views
TomSchmitz Themenstarter:in
16 Beiträge seit 2022
vor 2 Monaten
Migration von Blazor WASM .NET 7 zu Blazor "Auto" .NET 8

Hallo zusammen,

ich habe vor etwa einem halben Jahr ein Projekt mit ASP .NET Core Web API und Blazor WASM .NET 7 begonnen.

Nun ist .NET 8 erschienen und es scheinen sich einige Dinge verändert zu haben.

Zu diesen Dingen gehört offensichtlich auch der AuthenticationStateProvider.

Aktuell läuft mein ganzes Frontend-Auth System über diesen und Librarys, wie BlazoredLocalStorage.

Mir gelingt es einfach nicht mein aktuelles Projekt zu migrieren. 
Kennt eventuell jemand einen Beitrag, der dieses Problem angeht, oder kann mir anderweitig Tipps geben?

Hier sind ein paar Schnipsel, die Zeigen, wie mein aktuelles Projekt aufgebaut ist.


        public static async Task Main(string[] args)
       {
           var builder = WebAssemblyHostBuilder.CreateDefault(args);
           builder.RootComponents.Add<App>("#app");
           builder.RootComponents.Add<HeadOutlet>("head::after");
           builder.Services.AddBlazoredLocalStorage();
           //builder.Services.AddScoped<HttpClient>((_) => new HttpClient() { BaseAddress = new Uri("https://localhost:7266/") });
           builder.Services.AddHttpClient("Default", (x) => x.BaseAddress = new Uri("https://localhost:7266/"));
           builder.Services.AddScoped<TokenService>(); // Ändern Sie die Registrierung zu AddScoped
           builder.Services.AddTransient<AuthHandler>(); // AuthHandler als Transient Service registrieren
           builder.Services.AddHttpClient("AuthClient", (httpClient) =>
           {
               httpClient.BaseAddress = new Uri("https://localhost:7266/");
           })
           .ConfigurePrimaryHttpMessageHandler((services) =>
           {
               return services.GetRequiredService<AuthHandler>();
           });
           builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");
           builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthStateProvider>();
           builder.Services.AddAuthorizationCore();
           builder.Services.AddScoped<IAdminService, AdminService>();
           builder.Services.AddScoped<IAuthService, AuthService>();
           builder.Services.AddScoped<IUserProfileService, UserProfileService>();
           builder.Services.AddScoped<ILearningPathService, LearningPathService>();
           builder.Services.AddScoped<ICreationToolService, CreationToolService> ();
           builder.Services.AddScoped<LocalStorageService>();
           await builder.Build().RunAsync();
       }
public class CustomAuthStateProvider : AuthenticationStateProvider
{
   private readonly ILocalStorageService _localStorage;
   public CustomAuthStateProvider(ILocalStorageService localStorage, HttpClient http)
   {
       _localStorage = localStorage;
   }
   public override async Task<AuthenticationState> GetAuthenticationStateAsync()
   {
       string accessToken = await _localStorage.GetItemAsStringAsync("accessToken");
       var identity = new ClaimsIdentity();
       if (!string.IsNullOrEmpty(accessToken) && accessToken != "\"\"")
       {
           identity = new ClaimsIdentity(ParseClaimsFromJwt(accessToken), "jwt");
           var claims = ParseClaimsFromJwt(accessToken);
           foreach (var claim in claims)
           {
               if (claim.Type == ClaimTypes.Role)
               {
                   // Extrahiere Rollen aus dem JSON-Array im "Value" des Anspruchs
                   try
                   {
                       var rolesArray = JsonSerializer.Deserialize<List<string>>(claim.Value);
                       foreach (var role in rolesArray)
                       {
                           identity.AddClaim(new Claim(ClaimTypes.Role, role));
                       }
                   }
                   catch (JsonException)
                   {
                       // Fehler beim Deserialisieren des JSON-Arrays behandeln, falls erforderlich
                       // Hier können Sie geeignete Fehlerbehandlung durchführen oder die Rolle ignorieren
                   }
               }
           }
       }
       var user = new ClaimsPrincipal(identity);
       var state = new AuthenticationState(user);
       NotifyAuthenticationStateChanged(Task.FromResult(state));
       return state;
   }
   public static IEnumerable<Claim> ParseClaimsFromJwt(string jwt)
   {
       var payload = jwt.Split('.')[1];
       var jsonBytes = ParseBase64WithoutPadding(payload);
       var keyValuePairs = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonBytes);
       return keyValuePairs.Select(kvp => new Claim(kvp.Key, kvp.Value.ToString()));
   }
   private static byte[] ParseBase64WithoutPadding(string base64)
   {
       switch (base64.Length % 4)
       {
           case 2: base64 += "=="; break;
           case 3: base64 += "="; break;
       }
       return Convert.FromBase64String(base64);
   }
}
<CascadingAuthenticationState>
   <Router AppAssembly="@typeof(App).Assembly">
       <Found Context="routeData">
           <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
               <NotAuthorized>
                   @if (!context.User.Identity.IsAuthenticated)
                   {
                       <Redirect To="login"/>
                   }
                   else
                   {
                       <Redirect To="unauthorized" />
                   }
               </NotAuthorized>
           </AuthorizeRouteView>
           <FocusOnNavigate RouteData="@routeData" Selector="h1" />
       </Found>
       <NotFound>
           <PageTitle>Not found</PageTitle>
           <LayoutView Layout="@typeof(MainLayout)">
               <p role="alert">Sorry, there's nothing at this address.</p>
           </LayoutView>
       </NotFound>
   </Router>
</CascadingAuthenticationState>

Ansonsten verwende ich eben noch Tokenspeicherung via BlazoredLocalStorage. Aber ich denke der oben gezeigte Code, sollte für mein Problem am relevantesten sein.

Danke im voraus!

Hinweis von Abt vor 2 Monaten

Wenn man den HTML Code einfach mit XML deklariert und nicht mit C#, dann kann mans sogar lesen 😃

Wenn man etwas nicht einfach erklären kann, hat man es nicht verstanden.

-Albert Einstein

T
2.216 Beiträge seit 2008
vor 2 Monaten

Aus deinem Post geht nicht hervor was den das Problem bei der Migration ist.
Gibt es einen Fehler, fehlen Methoden etc.
Wenn nicht gerade zufällig jemand das gleiche Problem hat, dann dürfte es schwer werden dir zu helfen.

Ansonsten hilft immer der Blick in die Doku:
https://learn.microsoft.com/de-de/aspnet/core/blazor/security/?view=aspnetcore-8.0#authenticationstateprovider-service

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.774 Beiträge seit 2008
vor 2 Monaten

Also ich hab schon ein paar Custom AuthenticationStateProvider gesehen - aber noch nie sowas, wie Du es hast.
Wenn ich Dinge wie

 accessToken != "\"\""

sehe oder auch das Base64 Zeug, dann schrillen so paar Alarmglocken bei mir. Das lädt ja de-facto dazu ein, dass das knallt oder exploitet wird.

Was soll das denn alles sein, ein hybrides Auth Modell?

Ansonsten auch keine Ahnung, was Dein Issue ist, weil Du es nirgends beschreibst.

TomSchmitz Themenstarter:in
16 Beiträge seit 2022
vor 2 Monaten

Naja, wie gesagt.. Ich weiß nicht, wie ich den AuthStateProvider richtig in .NET 8 "Auto" einbinden soll.

Ich finde die Grenzen zwischen Blazor Server und Blazor WASM in der Blazor Web App (.NET 8) etwas komisch. Ich finde mich da noch nicht so zurecht.

Jedenfalls bräuchte ich ggf. eine Anleitung aus dem Internet oder so, wo beschrieben wird, wie man ein Auth-System (nicht Identity) in Blazor .NET 8 "Auto" umsetzt. Ich denke das würde am meisten helfen.

Ich möchte auch nur migrieren, weil ich von SSR profitieren möchte.

Wenn man etwas nicht einfach erklären kann, hat man es nicht verstanden.

-Albert Einstein

T
2.216 Beiträge seit 2008
vor 2 Monaten

Und was genau ist das Problem bei deinem jetzigen Code/Ansatz?
Wenn du nicht sagst wo es Probleme/Fehler gibt, kannst du ewig auf eine Antwort warten.
Ebenfalls wirst du kaum für deinen Ansatz eine 1:1 Anleitung finden, da es vermutlich zig Ansätze gibt, die alle zum gleichen führen können.

Ansonsten wäre es ggf. hilfreich zu erklären was dein "Auto" sein soll.
Meinst du damit den nahtlosen Übergang zwischen Blazor Server und WebAseembly.
Dann wäre immer noch unklar was genau das Problem ist.

Anbei hast du oben die Doku bekommen.
Da hast du schon einen Ansatz, musst du nur mal lesen und schauen ob es für dich passt.
Beispiel gibt es dort auch.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

TomSchmitz Themenstarter:in
16 Beiträge seit 2022
vor 2 Monaten

Moin T-Virus.

Ich meine die Integration ein Projekt, was du bekommst, wenn du die Blazor Web-App Vorlage verwendest und als interactive render mode "Auto" wählst.

Ich kann dir mein Problem auch nur schwerlich mit Code erklären, da es so gesehen keinen fehlerhaften Code gibt und das Projekt schlichtweg zu groß ist, um es hier mal eben zu posten.

Wenn du dir mal ein Blazor WASM-Projekt anschaust (.NET 7) siehst du, dass es anders von der Struktur ist.

Ich war jetzt einfach von der neuen Struktur verwundert.

Sprich, gehört der Auth-State-Provider nun in das Client-Projekt, der Blazor Web App, oder in das "Base"-Project?

Zudem ist die App.razor aus .NET 7 auf einmal zu einer Routes.razor geworden, wo auch wieder vieles verschieden ist. Ich finde z.B. die CascadingAuthenticationState nicht mehr.

Wenn man etwas nicht einfach erklären kann, hat man es nicht verstanden.

-Albert Einstein

TomSchmitz Themenstarter:in
16 Beiträge seit 2022
vor 2 Monaten

Also ich habe jetzt schon viel rausbekommen. Aber diese Auth-Provider...

Wenn man etwas nicht einfach erklären kann, hat man es nicht verstanden.

-Albert Einstein