[英]ASP.NET Core authentication broken after upgrade to 3.0
I have the following code, which worked fine under ASP.NET Core 2.2 (edited to remove product-specific naming)我有以下代码,在 ASP.NET Core 2.2 下运行良好(已编辑以删除特定于产品的命名)
public class Type1AuthenticationOptions : AuthenticationSchemeOptions {
public string Secret { get; set; }
}
public class Type1AuthenticationHandler : AuthenticationHandler<Type1AuthenticationOptions> {
public Type1AuthenticationHandler (IOptionsMonitor<Type1AuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
: base(options, logger, encoder, clock)
{ }
protected override Task<AuthenticateResult> HandleAuthenticateAsync() {
..
}
}
// Repeat for Type2AuthenticationHandler
My controllers were annotated thusly:我的控制器是这样注释的:
[Route("api/thing")]
[Authorize(AuthenticationSchemes = "type1")]
public class ThingController : Controller {
...
}
[Route("api/thing2")]
[Authorize(AuthenticationSchemes = "type2")] // different way of authorizing for thing2
public class Thing2Controller : Controller {
...
}
As above, this all worked great under Asp.NET Core 2.2 as well as prior version 2.1 and I think 2.0.如上所述,这一切都在 Asp.NET Core 2.2 以及之前的版本 2.1 和我认为 2.0 下运行良好。 The key parts (Configure and ConfigureServices are below)
关键部分(Configure 和 ConfigureServices 如下)
Upon upgrade to Asp.NET Core 3.0, the code all still compiles - all the classes, attributes and structure still exist, however my Authentication Handler is never getting called.升级到 Asp.NET Core 3.0 后,代码仍然可以编译——所有的类、属性和结构仍然存在,但是我的身份验证处理程序永远不会被调用。 If I put a breakpoint in the constructor of
Type1AuthenticationHandler
it doesn't even get hit.如果我在
Type1AuthenticationHandler
的构造函数中放置一个断点,它甚至不会被命中。
My entire Configure() method method is as follows:我的整个 Configure() 方法方法如下:
public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseAuthentication();
app.UseAuthorization();
app.UseRouting();
app.UseEndpoints(endpoints => {
endpoints.MapControllers();
});
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
}
// Middleware to set the no-cache header value on ALL requests
app.Use((context, next) => {
context.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue { NoCache = true };
return next();
});
And my ConfigureServices is我的 ConfigureServices 是
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddControllers() // no views to be had here. Turn it off for security
.AddNewtonsoftJson(opts => {
opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
opts.SerializerSettings.Converters.Add(new StringEnumConverter { NamingStrategy = new CamelCaseNamingStrategy() });
});
services
.AddAuthentication() // no default scheme, controllers must opt-in to authentication
.AddScheme<Type1AuthenticationOptions, Type1AuthenticationHandler>("type1", o =>
{
o.Secret = Configuration.GetThing1Secret();
})
.AddScheme<Type2AuthenticationOptions, Type2AuthenticationHandler>("type2", o =>
{
o.Secret = Configuration.GetThing2Secret();
});
services.AddAuthorization();
services.AddDbContext<DatabaseContext>(
options => options.UseNpgsql(Configuration.GetDatabaseConnectionString()),
ServiceLifetime.Transient);
// Used for fire and forget jobs that need access to the context outside of the
// the HTTP request that initiated the job
services.AddTransient(provider =>
new Func<DatabaseContext>(() => {
var options = new DbContextOptionsBuilder<DatabaseContext>()
.UseNpgsql(Configuration.GetDatabaseConnectionString())
.UseLoggerFactory(provider.GetRequiredService<ILoggerFactory>())
.Options;
return new DatabaseContext(options);
})
);
// make the configuration available to bits and pieces that may need it at runtime.
// Note: Generally it's bad practice to use this, you should configure your thing here, and inject the configured-thing instead
services.AddSingleton(Configuration);
services.AddMemoryCache();
// some more app-specific singleton services added but not relevant here
}
Any help much appreciated非常感谢任何帮助
PS on a long-shot, here's my csproj PS 远射,这是我的 csproj
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<UserSecretsId>99f957da-757d-4749-bd65-2b86753821a6</UserSecretsId>
<!-- SonarQube needs this but it's otherwise irrelevant for dotnet core -->
<ProjectGuid>{39054410-1375-4163-95e9-00f08b2efe2e}</ProjectGuid>
</PropertyGroup>
<PropertyGroup>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AWSSDK.S3" Version="3.3.104.31" />
<PackageReference Include="AWSSDK.SimpleNotificationService" Version="3.3.101.68" />
<PackageReference Include="AWSSDK.SimpleSystemsManagement" Version="3.3.106.12" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.WindowsServices" Version="3.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.0.0" PrivateAssets="all">
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.0.0" />
<PackageReference Include="AWSSDK.Extensions.NETCore.Setup" Version="3.3.100.1" />
<PackageReference Include="AWSSDK.SimpleEmail" Version="3.3.101.50" />
<PackageReference Include="NLog" Version="4.6.7" />
<PackageReference Include="NLog.Web.AspNetCore" Version="4.8.5" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.0.0-preview9" />
<PackageReference Include="Portable.BouncyCastle" Version="1.8.5" />
<PackageReference Include="System.IO.FileSystem.DriveInfo" Version="4.3.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="3.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Filter" Version="1.1.2" />
</ItemGroup>
</Project>
After taking another more detailed look at the migration guide, I noticed this:在再次更详细地查看迁移指南后,我注意到了这一点:
If the app uses authentication/authorization features such as AuthorizePage or [Authorize], place the call to UseAuthentication and UseAuthorization after UseRouting (and after UseCors if CORS Middleware is used).
如果应用程序使用 AuthorizePage 或 [Authorize] 等身份验证/授权功能,请在 UseRouting 之后(如果使用 CORS 中间件,则在 UseCors 之后)调用 UseAuthentication 和 UseAuthorization。
The trick (which is not mentioned in the migration guide) appears to be that UseAuthentication/UseAuthorization needs to be AFTER UseRouting but BEFORE UseEndpoints.诀窍(迁移指南中没有提到)似乎是 UseAuthentication/UseAuthorization 需要在 UseRouting 之后但在 UseEndpoints 之前。
This works now:这现在有效:
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints => {
endpoints.MapControllers();
});
If you place the Auth calls after UseEndpoints then you get an error about missing middleware如果您在 UseEndpoints 之后进行 Auth 调用,则会收到有关缺少中间件的错误
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.