using System;
using Ban.Sdaid.Notation.Documents;
namespace Ban.Sdaid.Icd.Domain.Access
{
/// <summary>Активный токен — учёт выписанного при входе JWT по его уникальному jti.</summary>
[DomainEntity]
public class UserActiveToken
{
/// <summary>Идентификатор записи.</summary>
public Guid Id { get; init; }
/// <summary>Уникальный идентификатор токена (claim jti) — ключ сессии и ключ кэша контекста.</summary>
public string Jti { get; init; }
/// <summary>Момент выписки.</summary>
public DateTime IssuedAt { get; init; }
/// <summary>Момент истечения.</summary>
public DateTime ExpiresAt { get; init; }
}
/// <summary>Отозванный токен — учёт вышедших/аннулированных сессий по jti (чёрный список).</summary>
[DomainEntity]
public class UserInvalidatedToken
{
/// <summary>Идентификатор записи.</summary>
public Guid Id { get; init; }
/// <summary>jti отозванного токена.</summary>
public string Jti { get; init; }
/// <summary>Момент отзыва.</summary>
public DateTime InvalidatedAt { get; init; }
/// <summary>Причина отзыва (выход, административный отзыв).</summary>
public string Reason { get; init; }
}
/// <summary>Описание доменных сущностей <see cref="UserActiveToken"/> и <see cref="UserInvalidatedToken"/>.</summary>
public class UserTokenSpec : IDomainEntityDocument
{
public Type Entity => typeof(UserActiveToken);
public string Name => "Токены сессии";
public string Description =>
@"Учёт выписанных и отозванных токенов по jti. Даёт настоящий выход: токен можно аннулировать до истечения, а его контекст — вытеснить из кэша.";
public string Version => "0.1";
public string Status => "draft";
public string[] Comments => new string[0];
public static string S1_Purpose = """
## Назначение
JWT сам по себе действителен до истечения — отозвать его нельзя. Чтобы выход был настоящим,
Сервис ведёт две парные записи по `jti`:
- **активный токен** — появляется при входе; по нему кэшируется контекст пользователя;
- **отозванный токен** — появляется при выходе/аннулировании; запрос с таким `jti`
отклоняется (401), даже если срок ещё не вышел.
`jti` — общий ключ: он и в токене, и в записи, и в ключе кэша контекста.
""";
public static string S2_Invariants = """
## Инварианты
- `jti` уникален среди активных токенов.
- Выход переносит запись из активных в отозванные и вытесняет контекст из кэша.
- Истёкшие активные записи подчищаются (не копятся бесконечно).
""";
public static string S99_Related = $"""
## Связанные артефакты
- {nameof(Ban.Sdaid.Icd.Arch.Tech.CSharp.ADR_SRV_006_AuthImplementation)} — выпуск, кэш контекста, чёрный список.
""";
}
}