Blazor WebAssembly - 找不到适合类型“JwtSecurityTokenHandler”的构造函数
Posted
技术标签:
【中文标题】Blazor WebAssembly - 找不到适合类型“JwtSecurityTokenHandler”的构造函数【英文标题】:Blazor WebAssembly - Suitable constructor for type 'JwtSecurityTokenHandler' could not be located 【发布时间】:2020-10-23 22:49:00 【问题描述】:编辑:10-27-20 我正在重写这篇文章,因为经过一个多星期后,我现在对问题和解决方案都有了更好的理解。 第一个问题: 暴击:Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] 未处理的异常呈现组件:找不到适合类型“System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler”的构造函数。确保类型是具体的,并且为公共构造函数的所有参数注册了服务。 System.InvalidOperationException:找不到适合类型“System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler”的构造函数。确保类型是具体的,并且为公共构造函数的所有参数注册了服务。 在 Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(Microsoft.Extensions.DependencyInjection.ServiceLookup.ResultCache 生命周期,System.Type serviceType,System.Type implementationType,Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteChain callSiteChain)在:0
... 最初我虽然这与 Azure 相关联,但事实并非如此。它与在 Release 而非 Debug 下编译我的项目有关。
下面的旧选择 - 请忽略并跳转到答案 =>
当我在我的计算机上测试我的 Blazor 应用程序时,我没有收到任何错误,但是一旦我发布到我的 Azure 应用程序服务,我就会收到很长的错误集...
暴击:Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] 未处理的异常呈现组件:找不到适合类型“System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler”的构造函数。确保类型是具体的,并且为公共构造函数的所有参数注册了服务。 System.InvalidOperationException:找不到适合类型“System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler”的构造函数。确保类型是具体的,并且为公共构造函数的所有参数注册了服务。 在 Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(Microsoft.Extensions.DependencyInjection.ServiceLookup.ResultCache 生命周期,System.Type serviceType,System.Type implementationType,Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteChain callSiteChain)在:0
...
我了解注入系统正在寻找 JwtSecurityTokenHandler,但无法找到。我对没有 Web UI 的旧 MVC API 使用相同的配置,它工作得很好,就像我说它在我的本地系统上工作,但在 Azure 上我得到一个错误。我知道我遗漏了一些简单的东西,但我找不到。
感谢您查看这个。
public void ConfigureServices(IServiceCollection services)
//Other DI Here
services.AddScoped<JwtSecurityTokenHandler>();
services.AddAuthentication(options =>
// Identity made Cookie authentication the default.
// However, we want JWT Bearer Auth to be the default.
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
)
.AddJwtBearer(cfg =>
// Configure JWT Bearer Auth to expect our security key
cfg.TokenValidationParameters =
new TokenValidationParameters
LifetimeValidator = (before, expires, token, param) =>
return expires > DateTime.UtcNow;
,
ValidateAudience = true,
ValidateIssuer = true,
ValidateLifetime = true,
ValidIssuer = Configuration["JwtIssuer"],
ValidAudience = Configuration["JwtAudience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtSecretKey"]))
;
);
services.AddScoped<IInventoryAdjustmentRepository, InventoryAdjustmentRepository>();
services.AddScoped<IEmployeeDataRepository, EmployeeDataRepository>();
services.AddScoped<IPartDataRepository, PartDataRepository>();
services.AddScoped<IInventoryScheduleRepository, InventoryScheduleRepository>();
编辑:客户端配置
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.Services.AddScoped<JwtSecurityTokenHandler>();
builder.Services.AddScoped<ApiAuthStateProvider, ApiAuthStateProvider>();
builder.Services.AddScoped<AuthenticationStateProvider>(p => p.GetService<ApiAuthStateProvider>());
builder.Services.AddTransient<IAuthenticationContract, UserServices>();
builder.Services.AddTransient<IEmployeeDataContract, EmployeeService>();
builder.Services.AddTransient<IPartRepository, PartRepository>();
builder.Services.AddTransient<IInventorySchedule, InventorySchedule>();
builder.Services.AddSingleton<IBrowserLocalStorage, BrowserLocalStorage>();
builder.Services.AddSingleton<IBrowserSessionStorage, BrowserSessionStorage>();
builder.Services.AddAuthorizationCore();
builder.Services.AddSyncfusionBlazor();
//Syncfusion.Licensing...
builder.RootComponents.Add<App>("app");
builder.Services.AddScoped(sp => new HttpClient BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) );
builder.Services.AddApiAuthorization();
await builder.Build().RunAsync();
【问题讨论】:
您已经按照this question and answer 建议的方式进行操作了……所以我唯一可以贡献的就是指出用户曾对其他问题的评论……他说:“你不应该注入它。JwtSecurityTokenHandler
有一个无参数的构造函数,不是一次性的,并且具有与其父级相同的生命周期。只是new
它“......我无法提供任何想法或理由为什么它在本地工作但不在 Azure 中。
感谢您的建议。我也读到了,对反应感到困惑。确实,您使用新令牌创建了令牌,但这个问题似乎出在 DI 中,而不是创建令牌。话虽如此,我认为问题出在客户端应用程序上,而不是服务器 API 上。我可以使用邮递员获取令牌并访问服务器上的授权 API 端点。我正在调查客户端的 DI。这是我第一次使用 Blazor Web 程序集,开始时我选择了“一体化”模板。我将很快用我的客户端配置编辑我的帖子,看看这是否是我的问题。
【参考方案1】:
编辑:10-27-20 我的项目是默认的 Blazor WebAssembly (PWA),没有身份验证和 .net 核心托管后端。身份验证是使用 JwtSecurityTokenHandler 作为其主要身份验证创建的 为了缩小范围,问题出在客户端 (UI) 代码中。为了解决客户端内部的问题,我做了如下改动。
解决方案: 在重载的 AuthenticationStateProvider 中,我创建了一个新的令牌处理程序,而不是像原来那样使用 DI。
public class ApiAuthStateProvider : AuthenticationStateProvider
//Here was the 1st issue
private readonly JwtSecurityTokenHandler _tokenHandler = new JwtSecurityTokenHandler();
private readonly IBrowserLocalStorage _localStorage;
private readonly HttpClient client;
private readonly IBrowserSessionStorage _sessionStorage;
public ApiAuthStateProvider(IBrowserLocalStorage localStorage, HttpClient _client, IBrowserSessionStorage sessionStorage)
client = _client;
_sessionStorage = sessionStorage;
_localStorage = localStorage;
...
接下来我在https://github.com/mono/linker/issues/870 上发现了其他人遇到类似问题的地方。 它指示在主程序中添加以下内容将防止链接器杀死 JwtSecurityTokenHandler:
_ = new JwtHeader();
_ = new JwtPayload();
最后,在主代码中我删除了以下行,因为我不再使用 DI:
builder.Services.AddScoped<JwtSecurityTokenHandler>();
现在它适用于任何地方发布、调试、Azure、本地......
请忽略下面的所有内容...与解决问题无关。
找到我的解决方案...最终问题与代码无关。
我认为该问题与您创建应用程序时创建的默认应用程序设置有关 Azure App Service,但我同时做了几处更改。我在下面概述了我的所有更改。
配置 -> 常规设置
-
平台:32 位到 64 位
始终开启:关闭到开启
配置 -> 应用程序设置
-
我删除了在应用创建/首次发布期间添加的默认 6 项
我在拍摄此屏幕截图并通过 Azure 门户添加我的数据库和应用程序见解后返回
扩展:添加 ASP.NET Core 3.0 和 3.1 运行时
这些已经是我几天前所做的事情了,但以防我想确保我列出了我的所有自定义项毕竟,我回到概述并在顶部栏上重新启动。然后我回到我的页面,没有错误!我还重新发布了几次,恢复了我所有的代码更改,它继续工作。
【讨论】:
以上是关于Blazor WebAssembly - 找不到适合类型“JwtSecurityTokenHandler”的构造函数的主要内容,如果未能解决你的问题,请参考以下文章
如何在 GitLab Pages 中将 Blazor WebAssembly 部署为静态站点
如何在 AWS S3/CDN 中托管具有环境特定值的 Blazor Webassembly