C# 具有WebAPI身份验证的.NET 5 Blazor服务器端和WebAssembly(混合版)?

C# 具有WebAPI身份验证的.NET 5 Blazor服务器端和WebAssembly(混合版)?,c#,authentication,blazor-server-side,blazor-webassembly,C#,Authentication,Blazor Server Side,Blazor Webassembly,有没有办法将默认身份验证(.NET 5/Identity Server)与Blazor服务器端和Blazor WebAssembly混合使用? 我想要一个Blazor项目,它可以在客户端(WebAssembly)和服务器端之间切换,为了保持客户端不变,我想要在客户端和服务器端使用WebAPI。我从服务器端开始(更好的调试和更好的表性能*),以后可能会切换到客户端(如果性能更好的话) *请不要开始讨论什么更好,或者如果您可能在WebAssembly方面有很好的性能,那么您没有很多嵌套组件,比如基于

有没有办法将默认身份验证(.NET 5/Identity Server)与Blazor服务器端Blazor WebAssembly混合使用? 我想要一个Blazor项目,它可以在客户端(WebAssembly)和服务器端之间切换,为了保持客户端不变,我想要在客户端和服务器端使用WebAPI。我从服务器端开始(更好的调试和更好的表性能*),以后可能会切换到客户端(如果性能更好的话)

*请不要开始讨论什么更好,或者如果您可能在WebAssembly方面有很好的性能,那么您没有很多嵌套组件,比如基于组件的表

我确实测试了这么多组合,但无法使其工作,但让我们从基本的开始:

  • 创建Blazor WebAssembly项目(ASP.Net核心托管)
  • 使用.NET 5进行身份验证(帐户)
  • 编辑Server startup.cs(如下所示)
  • 编辑Client program.cs(如下所示)
  • 将“\u Host.cshtml”添加到“\Server\Pages”(如下所示)
Startup.cs(服务器)

public void配置服务(IServiceCollection服务)
{
services.AddDbContext(options=>options.UseSqlServer(Configuration.GetConnectionString(“DefaultConnection”));
AddDatabaseDeveloperPageExceptionFilter();
services.AddDefaultIdentity(options=>options.SignIn.RequireConfirmedAccount=true);
services.AddIdentityServer().AddApiAuthorization();
services.AddAuthentication().AddIdentityServerJwt();
//服务器端支持
AddServerSideBlazor();
services.AddApiAuthorization();
如果(!services.Any(x=>x.ServiceType==typeof(HttpClient)))
{
services.AddScoped(s=>
{
var uriHelper=s.GetRequiredService();
返回新的HttpClient
{
BaseAddress=new System.Uri(uriHelper.BaseUri)
};
});
}
// --
services.AddControllersWithViews();
services.AddRazorPages();
}
public void配置(IApplicationBuilder应用程序、IWebHostEnvironment环境)
{
if(env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
app.UseWebAssemblyDebugging();
}
其他的
{
app.UseExceptionHandler(“/Error”);
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseIdentityServer();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(端点=>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
//服务器端支持
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage(“/_Host”);//endpoints.MapFallbackToFile(“index.html”);
// --
});
}
Program.cs(客户端)

公共静态异步任务主(字符串[]args)
{
var builder=WebAssemblyHostBuilder.CreateDefault(args);
//builder.RootComponents.Add(“#app”);
builder.Services.AddHttpClient(“BlazorSwitchWithSec2.ServerAPI”,client=>client.BaseAddress=新Uri(builder.HostenEnvironment.BaseAddress))
.AddHttpMessageHandler();
//向服务器项目发出请求时,提供包含访问令牌的HttpClient实例
builder.Services.addScope(sp=>sp.GetRequiredService().CreateClient(“BlazorSwitchWithSec2.ServerAPI”);
builder.Services.AddApiAuthorization();
等待builder.Build().RunAsync();
}
\u Host.cshtml(服务器)

@page/“
@addTagHelper*,Microsoft.AspNetCore.Mvc.TagHelpers
@if(Request.QueryString.Value.ToLower()包含(“mode=client”))
{
网络应用程序(CE)
}
其他的
{
网络应用程序(SE)
}
@if(Request.QueryString.Value.ToLower()包含(“mode=client”))
{
register('service-worker.js');
}
其他的
{
}
如果我试图通过WebAssembly或服务器注册或登录,则会出现以下错误:
无法将类型为“Microsoft.AspNetCore.Components.Server.ServerAuthenticationStateProvider”的对象强制转换为类型为“Microsoft.AspNetCore.Components.WebAssembly.Authentication.IRemoteAuthenticationService`1[Microsoft.AspNetCore.Components.WebAssembly.Authentication.RemoteAuthenticationState]”的对象。

也许这也有帮助:我尝试了一些不同的方法,比如使用客户端的服务,一种组合似乎可以与没有[Authorize]属性的控制器一起工作,但是使用它,我遇到了一个错误,比如
无法解析…
-结果是一个登录url(这就是解析无法工作的原因)。我不能发布代码,因为我测试了太多,项目不再工作了


没有任何身份验证,一切正常,我可以向WebAPI发送令牌来创建自己的登录系统。但是我想试试默认的。

这些卡尔·富兰克林的Blazor Train视频可能会对你有所帮助

Blazor同步性;同时开发服务器和WASM应用程序

Blazor同步性5.0


卡尔·富兰克林的这些Blazor Train视频可能会对您有所帮助

Blazor同步性;同时开发服务器和WASM应用程序

Blazor同步性5.0


我不喜欢BlazorServer引用BlazorWasm的方法。我更希望BlazorServer和BlazorWasm项目都引用一个包含应用程序的dll(rdl),这样可以更清楚地看出两者都在使用一个共享的代码库,并且可以避免BlazorServer从BlazorWasm中引入不必要的依赖项。 你可以查看这个链接 public void ConfigureServices(IServiceCollection services) { services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddDatabaseDeveloperPageExceptionFilter(); services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true).AddEntityFrameworkStores<ApplicationDbContext>(); services.AddIdentityServer().AddApiAuthorization<ApplicationUser, ApplicationDbContext>(); services.AddAuthentication().AddIdentityServerJwt(); // SERVER SIDE SUPPORT services.AddServerSideBlazor(); services.AddApiAuthorization(); if (!services.Any(x => x.ServiceType == typeof(HttpClient))) { services.AddScoped(s => { var uriHelper = s.GetRequiredService<NavigationManager>(); return new HttpClient { BaseAddress = new System.Uri(uriHelper.BaseUri) }; }); } // -- services.AddControllersWithViews(); services.AddRazorPages(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseMigrationsEndPoint(); app.UseWebAssemblyDebugging(); } else { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseBlazorFrameworkFiles(); app.UseStaticFiles(); app.UseRouting(); app.UseIdentityServer(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); endpoints.MapControllers(); // SERVER-SIDE SUPPORT endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("/_Host"); //endpoints.MapFallbackToFile("index.html"); // -- }); }
public static async Task Main(string[] args)
{
    var builder = WebAssemblyHostBuilder.CreateDefault(args);
    //builder.RootComponents.Add<App>("#app");

    builder.Services.AddHttpClient("BlazorSwitchWithSec2.ServerAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
        .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

    // Supply HttpClient instances that include access tokens when making requests to the server project
    builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("BlazorSwitchWithSec2.ServerAPI"));

    builder.Services.AddApiAuthorization();

    await builder.Build().RunAsync();
}
@page "/"
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
        @if (Request.QueryString.Value.ToLower().Contains("mode=client"))
        {
            <title>WebApp (CE)</title>
        }
        else
        {
            <title>WebApp (SE)</title>
        }
        <base href="~/" />
        <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
        <link href="css/app.css" rel="stylesheet" />
    </head>

    <body>
        @if (Request.QueryString.Value.ToLower().Contains("mode=client"))
        {
            <component type="typeof(BlazorSwitchWithSec2.Client.App)" render-mode="WebAssemblyPrerendered" />
            <script src="_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js"></script>
            <script src="_framework/blazor.webassembly.js"></script>
            <script>navigator.serviceWorker.register('service-worker.js');</script>
        }
        else
        {
            <component type="typeof(BlazorSwitchWithSec2.Client.App)" render-mode="Server" />
            <script src="_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js"></script>
            <script src="_framework/blazor.server.js"></script>
        }
    </body>
</html>