Реализуем Немедленный Отзыв Токенов в .NET 10. Окончание
Начало
Настройка токенов
Переключение клиента на использование референтных токенов - одна строка конфигурации. При определении клиента в IdentityServer установите AccessTokenType:
new Client
{
ClientId = "banking_app",
ClientSecrets = { new Secret("secret".Sha256()) },
AllowedGrantTypes = GrantTypes.Code,
// Вот эта строка
AccessTokenType = AccessTokenType.Reference,
AllowOfflineAccess = true,
RedirectUris = { "https://banking.example.com/signin-oidc" },
AllowedScopes = { "openid", "profile", "accounts.read", "transfers.write" }
};
Теперь токены, выданные этому клиенту, будут представлять собой непрозрачные дескрипторы вместо самодостаточных JWT.
Настройка API для интроспекции
Ваш API должен знать, как проверять эти непрозрачные токены. Вместо (или в дополнение к) проверке JWT настроим интроспекцию OAuth 2.0. Сначала определите ресурс API с секретом, который API будет использовать для аутентификации с конечной точкой интроспекции:
new ApiResource("banking_api")
{
Scopes = { "accounts.read", "transfers.write" },
ApiSecrets = { new Secret("api_secret".Sha256()) }
};Затем в Program.cs вашего API зарегистрируйте обработчик интроспекции. Обратите внимание, что обработчик должен использовать ту же схему аутентификации, что и та, которую вы хотите использовать для интроспекции:
builder.Services.AddAuthentication("token")
.AddOAuth2Introspection("token", opts =>
{
opts.Authority = "https://identity.banking.example.com";
opts.ClientId = "banking_api";
opts.ClientSecret = "api_secret";
});Если вам необходимо поддерживать как JWT, так и референтные токены (например, во время миграции), вы можете зарегистрировать обработчики обоих типов и использовать переадресацию для направления токенов к нужному обработчику:
builder.Services.AddAuthentication("token")
.AddJwtBearer("token", opts =>
{
opts.Authority = "https://identity.banking.example.com";
opts.Audience = "banking_api";
opts.TokenValidationParameters.ValidTypes = ["at+jwt"];
opts.ForwardDefaultSelector = Selector.ForwardReferenceToken("introspection");
})
.AddOAuth2Introspection("introspection", opts =>
{
opts.Authority = "https://identity.banking.example.com";
opts.ClientId = "banking_api";
opts.ClientSecret = "api_secret";
});Отзыв токена
Теперь ваша система поддержки (или автоматизированный конвейер обнаружения угроз) сможет немедленно отозвать токен, используя конечную точку отзыва IdentityServer, которая реализует RFC 7009:
using Duende.IdentityModel.Client;
var client = new HttpClient();
var result = await client.RevokeTokenAsync(
new TokenRevocationRequest
{
Address = "https://identity.banking.example.com/connect/revocation",
ClientId = "banking_app",
ClientSecret = "secret",
Token = stolenAccessToken
});
if (result.IsError)
logger.LogError("Token revocation failed: {Error}", result.Error);
После отзыва токен удаляется из хранилища предоставленных прав IdentityServer. Следующий запрос на проверку подлинности от любого API подтвердит, что токен больше не активен.
Не забывайте: вы также можете (и должны) отозвать токен обновления пользователя, чтобы предотвратить незаметное получение клиентом нового токена доступа:
await client.RevokeTokenAsync(
new TokenRevocationRequest
{
Address = "https://identity.banking.example.com/connect/revocation",
ClientId = "banking_app",
ClientSecret = "secret",
Token = refreshToken
});
Обратите внимание, что как интроспекция, так и аннулирование генерируют события аудита, которые можно использовать для реализации журналов аудита в регулируемых отраслях.
Источник: https://duendesoftware.com/blog/20260428-the-emergency-stop-button-implementing-immediate-token-revocation-in-dotnet-10