Как настроить аутентификацию jwt с помощью TimeProvider в тестировании интеграции .NET 9 - Проверка токена не удастся с C#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Как настроить аутентификацию jwt с помощью TimeProvider в тестировании интеграции .NET 9 - Проверка токена не удастся с

Сообщение Anonymous »

Мое приложение - веб -API .net 9. Я настраиваю аутентификацию с помощью этого метода расширения < /p>

Код: Выделить всё

public static void SetupAuthentication(this IServiceCollection services)
{
var authSettings = services.BuildServiceProvider().GetService()?.Value;

// JWT Configuration
services
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.SaveToken = true;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = authSettings!.Jwt.Issuer,
ValidAudience = authSettings!.Jwt.Audience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(authSettings!.Jwt.Secret)),
ClockSkew = TimeSpan.Zero,
};
})
.AddGoogle(options =>
{
options.ClientId = authSettings!.Google.ClientId;
options.ClientSecret = authSettings!.Google.ClientSecret;
});
}
< /code>
в другом месте я регистрирую TimeProvider с < /p>
public static void RegisterServices(this IServiceCollection services)
{
services.AddScoped();

// used for time manipulation and testing
// we should use this instead of DateTime.Now
services.TryAddSingleton(TimeProvider.System);
}
Я использую метод в TokenService для создания JWT, которые можно использовать для доступа к API. Этот метод обычно выглядит так: < /p>

Код: Выделить всё

public AccessTokenResponse CreateAccessToken(ApplicationUser user, string[] roles)
{
List claims =
[
new(JwtRegisteredClaimNames.Sub, user.Id),
new(JwtRegisteredClaimNames.Email, user.Email!),
new(JwtRegisteredClaimNames.EmailVerified, user.EmailConfirmed.ToString()),
];
claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));

var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.Secret));
var credentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha512Signature);
var expiresAt = DateTime.UtcNow.AddMinutes(_jwtSettings.ExpiryInMinutes);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = expiresAt,
SigningCredentials = credentials,
Issuer = _jwtSettings.Issuer,
Audience = _jwtSettings.Audience,
};

var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
return new AccessTokenResponse(tokenHandler.WriteToken(token), expiresAt);
}
< /code>
Но теперь я хочу использовать TimeProvider, чтобы я мог проверить истечение срока действия токена плюс.  Поэтому я обновил метод, теперь выглядит так: < /p>
public AccessTokenResponse CreateAccessToken(ApplicationUser user, string[] roles)
{
List claims =
[
new(JwtRegisteredClaimNames.Sub, user.Id),
new(JwtRegisteredClaimNames.Email, user.Email!),
new(JwtRegisteredClaimNames.EmailVerified, user.EmailConfirmed.ToString()),
];
claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));

var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.Secret));
var credentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha512Signature);

var now = timeProvider.GetUtcNow();
var expiresAt = now.DateTime.AddMinutes(_jwtSettings.ExpiryInMinutes);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = expiresAt,
SigningCredentials = credentials,
Issuer = _jwtSettings.Issuer,
Audience = _jwtSettings.Audience,
NotBefore = now.DateTime,
IssuedAt = now.DateTime,
};

var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
return new AccessTokenResponse(tokenHandler.WriteToken(token), expiresAt);
}
Конечно, TimeProvider вводится в службу для разрешения DI Container. Теперь, когда я запускаю свои тесты, я получаю эту ошибку: < /p>

Код: Выделить всё

[Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler] - Bearer was not authenticated. Failure message: IDX10223: Lifetime validation failed. The token is expired. ValidTo (UTC): '12/31/1999 11:15:00 PM', Current time (UTC): '4/30/2025 3:06:23 PM'.

OR

System.ArgumentException: IDX12401: Expires: '01/01/2000 00:15:00' must be after NotBefore: '30/04/2025 08:08:05'.
at System.IdentityModel.Tokens.Jwt.JwtPayload.AddFirstPriorityClaims(String issuer, String audience, IList`1 audiences, Nullable`1 notBefore, Nullable`1 expires, Nullable`1 issuedAt)

< /code>
Я попытался установить TimeProvider в моей конфигурации аутентификации - не повезло. Я попытался установить значение для теперь и выпущено в SecurityTokendescriptor 
-Не удачи.public class CustomWebApplicationFactory : WebApplicationFactory, IAsyncLifetime
{
public readonly FakeTimeProvider FakeTimeProvider = new();

protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureTestServices(services =>
{
var timeProviderDescriptor = services.SingleOrDefault(d => d.ServiceType == typeof(TimeProvider));
if (timeProviderDescriptor != null)
{
services.Remove(timeProviderDescriptor);
services.AddSingleton(FakeTimeProvider);
}
});
}
}
< /code>
Я также пробовал инициализацию faketimeprovider с определенной датой - не удачи. Я делаю что -то не так? Есть ли конкретный способ настроить TimeProvider в интеграционных тестах?
Моя цель - использовать его везде, а не статические методы DateTime. < /P>

Подробнее здесь: https://stackoverflow.com/questions/796 ... tion-tests
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»