根据配置身份验证的方式,JWT或AzureAD身份验证在受保护的端点上工作,但其中一个总是失败,错误为"Object reference not set to an instance of an object".
我已经这样配置了我的DotNet核心Web API:
services
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
var jwtSettings = config.GetSection("SecuritySettings:JwtSettings").Get<JwtSettings>();
byte[] key = Encoding.ASCII.GetBytes(jwtSettings.Key);
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateLifetime = true,
ValidateAudience = false,
RoleClaimType = ClaimTypes.Role,
ClockSkew = TimeSpan.Zero
};
options.Events = new JwtBearerEvents
{
OnChallenge = context =>
{
context.HandleResponse();
if (!context.Response.HasStarted)
{
throw new UnauthorizedException("Authentication Failed.");
}
return Task.CompletedTask;
},
OnForbidden = _ => throw new ForbiddenException("You are not authorized to access this resource."),
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];
if (!string.IsNullOrEmpty(accessToken) &&
context.HttpContext.Request.Path.StartsWithSegments("/notifications"))
{
// Read the token out of the query string
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
})
.AddMicrosoftIdentityWebApi(config, "SecuritySettings:AzureAd", "AzureAD");
services.AddAuthorization(options =>
{
var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(
JwtBearerDefaults.AuthenticationScheme,
"AzureAD");
defaultAuthorizationPolicyBuilder =
defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
});
我打开了详细日志(log)记录:
[14:36:59 DBG] Entity Framework Core 7.0.12 initialized 'ApplicationDbContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL:7.0.11+c25a0d7b68d66c6ab3849a3b4333964faea6adc9' with options: SensitiveDataLoggingEnabled MigrationsAssembly=Migrators.PostgreSQL
[14:37:26 DBG] Compiling query expression:
'DbSet<ApplicationUser>()
.Where(u => u.ObjectId == __objectId_0)
.FirstOrDefault()'
[14:37:26 DBG] Generated query execution expression:
'queryContext =>
{
queryContext.AddParameter(
name: "__ef_filter__Id_0",
value: (object)Invoke(queryContext => ((ApplicationDbContext)queryContext.Context).TenantInfo.Id, queryContext));
return ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync<ApplicationUser>(
asyncEnumerable: new SingleQueryingEnumerable<ApplicationUser>(
(RelationalQueryContext)queryContext,
RelationalCommandCache.QueryExpression(
Projection Mapping:
EmptyProjectionMember -> Dictionary<IProperty, int> { [Property: ApplicationUser.Id (string) Required PK AfterSave:Throw, 0], [Property: ApplicationUser.AccessFailedCount (int) Required, 1], [Property: ApplicationUser.AuthenticationType (AuthenticationType?), 2], [Property: ApplicationUser.ConcurrencyStamp (string) Concurrency, 3], [Property: ApplicationUser.Email (string) MaxLength(256), 4], [Property: ApplicationUser.EmailConfirmed (bool) Required, 5], [Property: ApplicationUser.FirstName (string), 6], [Property: ApplicationUser.ImageUrl (string), 7], [Property: ApplicationUser.IsActive (bool) Required, 8], [Property: ApplicationUser.LastName (string), 9], [Property: ApplicationUser.LockoutEnabled (bool) Required, 10], [Property: ApplicationUser.LockoutEnd (DateTimeOffset?), 11], [Property: ApplicationUser.NormalizedEmail (string) Index MaxLength(256), 12], [Property: ApplicationUser.NormalizedUserName (string) Index MaxLength(256), 13], [Property: ApplicationUser.ObjectId (string) MaxLength(256), 14], [Property: ApplicationUser.PasswordHash (string), 15], [Property: ApplicationUser.PhoneNumber (string), 16], [Property: ApplicationUser.PhoneNumberConfirmed (bool) Required, 17], [Property: ApplicationUser.RefreshToken (string), 18], [Property: ApplicationUser.RefreshTokenExpiryTime (DateTime) Required, 19], [Property: ApplicationUser.SecurityStamp (string), 20], [Property: ApplicationUser.TenantId (string) Required Index MaxLength(64), 21], [Property: ApplicationUser.TwoFactorEnabled (bool) Required, 22], [Property: ApplicationUser.UserName (string) MaxLength(256), 23] }
SELECT TOP(1) u.Id, u.AccessFailedCount, u.AuthenticationType, u.ConcurrencyStamp, u.Email, u.EmailConfirmed, u.FirstName, u.ImageUrl, u.IsActive, u.LastName, u.LockoutEnabled, u.LockoutEnd, u.NormalizedEmail, u.NormalizedUserName, u.ObjectId, u.PasswordHash, u.PhoneNumber, u.PhoneNumberConfirmed, u.RefreshToken, u.RefreshTokenExpiryTime, u.SecurityStamp, u.TenantId, u.TwoFactorEnabled, u.UserName
FROM Identity.Users AS u
WHERE (u.TenantId == @__ef_filter__Id_0) && (u.ObjectId == @__objectId_0)),
null,
Func<QueryContext, DbDataReader, ResultContext, SingleQueryResultCoordinator, ApplicationUser>,
HIS.Simple.Sync.Infrastructure.Persistence.Context.ApplicationDbContext,
False,
False,
True
),
cancellationToken: queryContext.CancellationToken);
}'
[14:37:34 ERR] Exception occurred while processing message.
System.NullReferenceException: Object reference not set to an instance of an object.
at lambda_method340(Closure, QueryContext)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, Expression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.FirstOrDefaultAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at HIS.Simple.Sync.Infrastructure.Identity.UserService.GetOrCreateFromPrincipalAsync(ClaimsPrincipal principal) in C:\xxxxxxxxxx\src\Infrastructure\Identity\UserService.CreateUpdate.cs:line 31
at HIS.Simple.Sync.Infrastructure.Auth.AzureAd.AzureAdJwtBearerEvents.TokenValidated(TokenValidatedContext context) in C:\xxxxxxxxxx\src\Infrastructure\Auth\AzureAd\AzureAdJwtBearerEvents.cs:line 92
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
[14:37:34 ERR] Authentication failed Exception: System.NullReferenceException: Object reference not set to an instance of an object.
at lambda_method340(Closure, QueryContext)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, Expression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.FirstOrDefaultAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at HIS.Simple.Sync.Infrastructure.Identity.UserService.GetOrCreateFromPrincipalAsync(ClaimsPrincipal principal) in Cxxxxxxxxxxsrc\Infrastructure\Identity\UserService.CreateUpdate.cs:line 31
at HIS.Simple.Sync.Infrastructure.Auth.AzureAd.AzureAdJwtBearerEvents.TokenValidated(TokenValidatedContext context) in C:\xxxxxxxxxx\src\Infrastructure\Auth\AzureAd\AzureAdJwtBearerEvents.cs:line 92
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
此错误发生在函数ExecuteAsync中的Microsoft.EntityFrameworkCore.Query.Internal QueryCompiler.cs中:
当移除另一个时,两个都起作用.
在所述端点中执行的查询:
public async Task<UserDetailsDto> GetAsync(string userId, CancellationToken cancellationToken)
{
var user = await _userManager.FindByIdAsync(userId);
_ = user ?? throw new NotFoundException(_t["User Not Found."]);
return user.Adapt<UserDetailsDto>();
}
我也调试过这个,_userManager
和userid都不是空的.
我在这个项目中使用了Full Stack HERO网络API模板.
我试过调试,我试过切换配置,我试过使用不同的配置,比如AddOpenIdConnect
,但仍然有相同的错误.
身份验证应该结合使用JWT和AzureAD.我应该能够使用由其中之一生成的令牌来进行身份验证.
编辑:原来这是芬巴克的问题.多租户,但仍然需要帮助,因为我无法解决这个问题.