限制在 ASP.NET Core 的受保护负载的生存期Limit the lifetime of protected payloads in ASP.NET Core

本文内容

在某些情况下,应用程序开发人员需要创建在设定的时间段之后过期的受保护负载。例如,受保护的负载可能表示密码重置令牌,该令牌仅应在一小时内有效。当然,开发人员也可以创建自己的负载格式,其中包含一个嵌入的过期日期,而高级开发人员可能希望这样做,但对于大多数管理这些过期的开发人员来说,这种情况都很繁琐。

为了使我们的开发人员受众更容易,包AspNetCore包含用于创建在设定的时间段后自动过期的有效负载的实用工具 api。这些 Api 挂起 ITimeLimitedDataProtector 类型。

API 使用情况API usage

ITimeLimitedDataProtector 接口是用于保护和取消保护时间限制/自过期负载的核心接口。若要创建 ITimeLimitedDataProtector的实例,首先需要使用特定用途构造的常规IDataProtector的实例。IDataProtector 实例可用后,调用 IDataProtector.ToTimeLimitedDataProtector 扩展方法以获取具有内置过期功能的保护程序。

ITimeLimitedDataProtector 公开以下 API surface 和 extension 方法:

  • CreateProtector (string 目的): ITimeLimitedDataProtector-此 API 类似于现有 IDataProtectionProvider.CreateProtector,因为它可用于从根时间限制的保护程序创建用途链

  • 保护(byte [] 纯文本、DateTimeOffset 过期): byte []

  • 保护(byte [] 纯文本,TimeSpan 生存期): byte []

  • 保护(byte [] 纯文本): byte []

  • 保护(字符串纯文本、DateTimeOffset 过期):字符串

  • 保护(字符串纯文本、TimeSpan 生存期):字符串

  • 保护(字符串纯文本):字符串

除了使用纯文本的核心 Protect 方法之外,还有一些新的重载,可用于指定有效负载的到期日期。可以将到期日期指定为绝对日期(通过 DateTimeOffset)或指定为相对时间(从当前系统时间起,通过 TimeSpan)。如果调用不带过期的重载,则假定负载永不过期。

  • 取消保护(byte [] protectedData,out DateTimeOffset 过期): byte []

  • Unprotect(byte[] protectedData) : byte[]

  • 取消保护(string protectedData,out DateTimeOffset 过期):字符串

  • 取消保护(string protectedData):字符串

Unprotect 方法返回未受保护的原始数据。如果负载尚未过期,则将以可选的 out 参数形式返回绝对过期,并将其作为不受保护的原始数据。如果有效负载已过期,则解除保护方法的所有重载都将引发 System.security.cryptography.cryptographicexception。

警告

不建议使用这些 Api 来保护需要长期或无限持久性的负载。"我可以承受受保护的负载在一个月后永久无法恢复吗?"可以作为最佳经验法则;如果答案不是,开发人员应考虑其他 Api。

下面的示例使用非 DI 代码路径来实例化数据保护系统。若要运行此示例,请确保首先添加了对 AspNetCore 包的引用。

  1. using System;
  2. using System.IO;
  3. using System.Threading;
  4. using Microsoft.AspNetCore.DataProtection;
  5. public class Program
  6. {
  7. public static void Main(string[] args)
  8. {
  9. // create a protector for my application
  10. var provider = DataProtectionProvider.Create(new DirectoryInfo(@"c:\myapp-keys\"));
  11. var baseProtector = provider.CreateProtector("Contoso.TimeLimitedSample");
  12. // convert the normal protector into a time-limited protector
  13. var timeLimitedProtector = baseProtector.ToTimeLimitedDataProtector();
  14. // get some input and protect it for five seconds
  15. Console.Write("Enter input: ");
  16. string input = Console.ReadLine();
  17. string protectedData = timeLimitedProtector.Protect(input, lifetime: TimeSpan.FromSeconds(5));
  18. Console.WriteLine($"Protected data: {protectedData}");
  19. // unprotect it to demonstrate that round-tripping works properly
  20. string roundtripped = timeLimitedProtector.Unprotect(protectedData);
  21. Console.WriteLine($"Round-tripped data: {roundtripped}");
  22. // wait 6 seconds and perform another unprotect, demonstrating that the payload self-expires
  23. Console.WriteLine("Waiting 6 seconds...");
  24. Thread.Sleep(6000);
  25. timeLimitedProtector.Unprotect(protectedData);
  26. }
  27. }
  28. /*
  29. * SAMPLE OUTPUT
  30. *
  31. * Enter input: Hello!
  32. * Protected data: CfDJ8Hu5z0zwxn...nLk7Ok
  33. * Round-tripped data: Hello!
  34. * Waiting 6 seconds...
  35. * <<throws CryptographicException with message 'The payload expired at ...'>>
  36. */