У меня есть сервис по работе с JWT
public class JwtService : IJwtService
{
private IDistributedCache cache;
private IHttpContextAccessor httpContext;
private IOptions<JwtOptions> jwtOptions;
private MyContext context;
private ILogger<JwtService> logger;
public JwtService(MyContext context, IDistributedCache cache,
IHttpContextAccessor httpContext, IOptions<JwtOptions> jwtOptions, ILogger<JwtService> logger)
{
this.cache = cache;
this.httpContext = httpContext;
this.jwtOptions = jwtOptions;
this.context = context;
this.logger = logger;
}
private string GetCurrentJwtString()
{
StringValues header = httpContext.HttpContext.Request.Headers["authorization"];
return StringValues.IsNullOrEmpty(header) ? string.Empty : header.Single().Split(" ").Last();
}
public async Task<bool> IsActiveCurrentJwtAsync()
{
return await IsActiveJwtAsync(GetCurrentJwtString());
}
public async Task DeactivateCurrentJwtAsync()
{
await DeactivateJwtAsync(GetCurrentJwtString());
}
public async Task DeactivateJwtAsync(string token)
{
await cache.SetStringAsync(token, "diactivated", new DistributedCacheEntryOptions()
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(jwtOptions.Value.ExpiryMinutes)
});
}
public async Task<bool> IsActiveJwtAsync(string token)
{
return await cache.GetStringAsync(token) == null;
}
И есть два места в проекте, которые взаимодействуют с этим сервисом:
Первое. В контроллере пользователя при выходе из аккаунта я вызываю метод деактивации токена, который просто заносит токен в кэш.
[Authorize]
[Route("api/[controller]/[action]")]
[ApiController]
public class UserController : Controller
{
IJwtService jwtServ;
IUserService userServ;
public UserController(IJwtService jwtServ, IUserService userServ)
{
this.jwtServ = jwtServ;
this.userServ = userServ;
}
[ActionName("Logout")]
public async Task Logout()
{
await jwtServ.DeactivateCurrentJwtAsync();
}
}
И второе: В классе Startup в настройке аутентификации после валидации токена я проверяю, есть ли он в кэше или нет.
services.AddDistributedRedisCache(option =>
{
option.Configuration = Configuration["Redis:Address"];
option.InstanceName = "maelstorm";
});
services
.AddAuthentication(options => {
options.DefaultAuthenticateScheme = jwtSchemeName;
options.DefaultChallengeScheme = jwtSchemeName;
})
.AddJwtBearer(jwtSchemeName, jwtBearerOptions => {
jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingDecodingKey.GetKey(),
TokenDecryptionKey = encryptingDecodingKey.GetKey(),
ValidateIssuer = true,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidateAudience = true,
ValidAudience = Configuration["Jwt:Audience"],
ValidateLifetime = true,
ClockSkew = TimeSpan.FromSeconds(5)
};
var servProvider = services.BuildServiceProvider();
var jwtService = servProvider.GetService<IJwtService>();
jwtBearerOptions.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
{
context.Response.Headers.Add("Token-Expired", "true");
}
return Task.CompletedTask;
},
OnTokenValidated = async context =>
{
if(! await jwtService.IsActiveCurrentJwtAsync())
{
context.Fail("Token is not active");
}
}
};
Проблема заключается в том, что в первом случае переменная cache в JWTService имеет тип Microsoft.Extensions.Caching.Distributed.MemoryDistributedCache
,а во втором - Microsoft.Extensions.Caching.Redis.RedisCachе
. Получается, что метод деактивации токена записывает токен в один кэш, а метод проверки пытается достать из другого и поэтому ничего не работает. Почему механизм внедрения зависимостей создает экземпляры разных типов? Каким образом сделать так, чтобы всегда использовался лишь Redis в качестве кэша?
Механизм внедрения зависимостей создаёт разные зависимости потому что у вас два разных ServiceProvider: один был создан фреймворком, а другой создали вы сами:
// Не делайте так!
var servProvider = services.BuildServiceProvider();
var jwtService = servProvider.GetService<IJwtService>();
Вместо того, чтобы вызывать случайные методы, вам надо получить доступ к системному ServiceProvider. Например, вот так:
OnTokenValidated = async context =>
{
var jwtService = context.HttpContext.RequestServices.GetService<IJwtService>();
// ...
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
В моей программе есть вкладка, где я могу написать и запустить кодПри его запуске, появляется окошко с двумя TextBox'ами, в первом вывод, а во втором...
В данный момент при любом статусе оплаты или ее стадии осуществляется редирект на нужную страницу и все ок, но только при клике на "вернуться...
Есть следующий код, задача которого удалить данные из бдСейчас все данные удаляются при переходе по ссылке localhost/?id=666