Jac*_*kal 6 c# asp.net-core blazor
我不明白为什么我总是收到这个例外。我尝试保护 Blazor WebAssembly
blazor.webassembly.js:1 WASM: System.MissingMethodException: 找不到 Microsoft.AspNetCore.Components.Authorization.AuthorizeRouteView 类型的默认构造函数
应用程序.razor
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<CascadingAuthenticationState>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</CascadingAuthenticationState>
</NotFound>
</Router>
Run Code Online (Sandbox Code Playgroud)
这是客户端程序.cs
public class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
builder.Services.AddScoped<AuthenticationStateProvider, ApiAuthenticationStateProvider>();
builder.Services.AddAuthorizationCore(options => { });
await builder.Build().RunAsync();
}
}
Run Code Online (Sandbox Code Playgroud)
自定义身份验证状态提供程序
public class ApiAuthenticationStateProvider : AuthenticationStateProvider
{
private readonly HttpClient _httpClient;
private readonly ILocalStorageService _localStorage;
public ApiAuthenticationStateProvider(HttpClient httpClient, ILocalStorageService localStorage)
{
_httpClient = httpClient;
_localStorage = localStorage;
}
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
var savedToken = await _localStorage.GetItemAsync<string>("authToken");
if (string.IsNullOrWhiteSpace(savedToken))
{
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
}
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", savedToken);
return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(ParseClaimsFromJwt(savedToken), "jwt")));
}
public void MarkUserAsAuthenticated(string email)
{
ClaimsPrincipal authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, email) }, "apiauth"));
var authState = Task.FromResult(new AuthenticationState(authenticatedUser));
NotifyAuthenticationStateChanged(authState);
}
public void MarkUserAsLoggedOut()
{
var anonymousUser = new ClaimsPrincipal(new ClaimsIdentity());
var authState = Task.FromResult(new AuthenticationState(anonymousUser));
NotifyAuthenticationStateChanged(authState);
}
private IEnumerable<Claim> ParseClaimsFromJwt(string jwt)
{
var claims = new List<Claim>();
var payload = jwt.Split('.')[1];
var jsonBytes = ParseBase64WithoutPadding(payload);
var keyValuePairs = JsonSerializer.Deserialize<Dictionary<string, object>>(jsonBytes);
keyValuePairs.TryGetValue(ClaimTypes.Role, out object roles);
if (roles != null)
{
if (roles.ToString().Trim().StartsWith("["))
{
var parsedRoles = JsonSerializer.Deserialize<string[]>(roles.ToString());
foreach (var parsedRole in parsedRoles)
{
claims.Add(new Claim(ClaimTypes.Role, parsedRole));
}
}
else
{
claims.Add(new Claim(ClaimTypes.Role, roles.ToString()));
}
keyValuePairs.Remove(ClaimTypes.Role);
}
claims.AddRange(keyValuePairs.Select(kvp => new Claim(kvp.Key, kvp.Value.ToString())));
return claims;
}
private byte[] ParseBase64WithoutPadding(string base64)
{
switch (base64.Length % 4)
{
case 2: base64 += "=="; break;
case 3: base64 += "="; break;
}
return Convert.FromBase64String(base64);
}
}
Run Code Online (Sandbox Code Playgroud)
}
服务器启动.cs
public class Startup
{
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["JwtIssuer"],
ValidAudience = Configuration["JwtAudience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtSecurityKey"]))
};
});
services.AddBlazoredLocalStorage();
services.AddAuthorizationCore();
services.AddScoped<AuthenticationStateProvider, ApiAuthenticationStateProvider>();
services.AddScoped<IAuthService, AuthService>();
services.AddMvc();
services.AddResponseCompression(opts =>
{
opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
new[] { "application/octet-stream" });
});
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseResponseCompression();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBlazorDebugging();
}
app.UseStaticFiles();
app.UseClientSideBlazorFiles<Client.Program>();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
endpoints.MapFallbackToClientSideBlazor<Client.Program>("index.html");
});
}
}
Run Code Online (Sandbox Code Playgroud)
添加@using Microsoft.AspNetCore.Components.Authorization到 App.razor 文件的顶部。
将选项和授权服务添加到 Program.Main(客户端):
builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();
Run Code Online (Sandbox Code Playgroud)
注意:以下内容(客户端):
services.AddBlazoredLocalStorage();
services.AddAuthorizationCore();
services.AddScoped<AuthenticationStateProvider,
ApiAuthenticationStateProvider>();
services.AddScoped<IAuthService, AuthService>();
Run Code Online (Sandbox Code Playgroud)
属于客户端,而不是服务器,尽管最终它的配置相同......
注意:以下内容(客户端):
services.AddScoped<AuthenticationStateProvider,
ApiAuthenticationStateProvider>();
Run Code Online (Sandbox Code Playgroud)
应该是(客户端):
services.AddScoped<ApiAuthenticationStateProvider>();
services.AddScoped<AuthenticationStateProvider>(provider => provider.GetRequiredService<ApiAuthenticationStateProvider>());
Run Code Online (Sandbox Code Playgroud)
您应该注意 Startup 类中的顺序
更新:
正如我在下面的评论中建议的那样,禁用链接器似乎有效。然而,这应该是一个临时解决方案。这是禁用链接器的方法:<BlazorLinkOnBuild>false</BlazorLinkOnBuild>
通过禁用链接器,您可以防止删除未使用或未引用的代码,这可能是导致错误的原因......并且通过启用链接器,您可以允许这样做。然而,这段代码:
builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();
Run Code Online (Sandbox Code Playgroud)
应该阻止链接器剥离未引用的逻辑。更好的是,在 Program 类中添加自定义 AuthenticationStateProvider 实现:
builder.Services.AddScoped<AuthenticationStateProvider,
ApiAuthenticationStateProvider>();
Run Code Online (Sandbox Code Playgroud)
应该已经解决了这个问题。你是这样做的吗?
再次强调,禁用链接器是一个临时解决方案。
| 归档时间: |
|
| 查看次数: |
3266 次 |
| 最近记录: |