【发布时间】:2021-06-04 10:35:33
【问题描述】:
有没有办法以混合方式将默认身份验证 (.NET 5 / Identity-Server) 与 Blazor ServerSide 和 Blazor WebAssembly 结合使用? 我想要一个 Blazor 项目,它可以在 ClientSide (WebAssembly) 和 ServerSide 之间切换,以保持 Client 相同,我想在 ClientSide 和 ServerSide上使用 WebAPI。我从 ServerSide 开始(更好的调试和更好的表性能 *),以后可能会切换到 ClientSide(如果性能会更好)。
*请不要开始讨论什么更好,或者如果您可能在 WebAssembly 上有良好的性能,那么您没有很多嵌套组件,例如基于组件的表。
我确实测试了这么多组合,但无法让它发挥作用,但让我们从基础开始:
- 创建 Blazor WebAssembly 项目(托管 ASP.Net Core)
- 将 .NET 5 与身份验证(帐户)结合使用
- 编辑服务器 startup.cs(如下所示)
- 编辑客户端 program.cs(如下所示)
- 将“_Host.cshtml”添加到“\Server\Pages”(如下所示)
Startup.cs(服务器)
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");
// --
});
}
Program.cs(客户端)
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();
}
_Host.cshtml(服务器)
@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>
如果我尝试通过 WebAssembly 或服务器注册或登录,我会收到以下错误:
Unable to cast object of type 'Microsoft.AspNetCore.Components.Server.ServerAuthenticationStateProvider' to type 'Microsoft.AspNetCore.Components.WebAssembly.Authentication.IRemoteAuthenticationService`1[Microsoft.AspNetCore.Components.WebAssembly.Authentication.RemoteAuthenticationState]'
也许这也有帮助:我尝试了一些不同的方法,比如使用来自客户端的服务,一种组合似乎可以与没有 [Authorize] 属性的控制器一起使用,但是有了它,我得到了一个类似 Unable to parse ... 的错误 - 结果是登录网址(这就是解析不起作用的原因)。我不能发布代码,因为我测试了太多,项目不再工作了。
没有任何身份验证一切正常,我可以向 WebAPI 发送一个令牌来创建我自己的登录系统。但是我想试试默认的。
【问题讨论】:
-
虽然你对它们进行相同的编程,但是服务器端和 wasm 是完全不同的。由于 wasm 在客户端浏览器中天真地运行,因此需要一种不同的身份验证方法。
-
我知道,默认代码在客户端工作正常(如果我不更改任何内容)。服务器端“只是”缺少一个部分来告诉“使用您的 cookie / 存储并将您的数据发送到 api”。我的意思是默认的服务器端代码也可以工作(使用身份验证),但没有 API 访问权限。而且它们之间的(代码)差异似乎很小。
标签: c# authentication blazor-server-side blazor-webassembly