Identity 的 UserManager 什么时候不支持锁定?

When does Identity's UserManager not support lockouts?

ASP.NET Core Identity UserManager.SupportsUserLockout(),对我来说是真的。

描述:

Gets a flag indicating whether the backing user store supports user lock-outs.

用户管理器是否可能不支持锁定?

Is it ever possible for the user manager NOT to support lockouts?

在这两种情况中的任何一种情况下:

  • UserManager<TUser> 被子classed 并且 virtual bool SupportsUserLockout 属性 被覆盖并且该实现 returns false.
  • UserManager<TUser>.Store(您的 IUserStore<TUser> 实现)没有实现 optional IUserLockoutStore<TUser> 接口。

  • 如果您正在使用“stock”in-box ASP.NET Core Identity 功能,而不使用任何自定义 IUserStore 实现(并且没有子classing UserManager<TUser>),那么你的运行时 IUserStore<TUser> 将是一些 subclass of abstract class UserStoreBase<...> 实现了 IUserLockoutStore<TUser>
    • 例如ASP.NET Entity Framework 的核心标识使用 Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserOnlyStore 继承了 IUserLockoutStore<TUser> 接口实现。
  • 因为在 C#/.NET 中,接口是严格可加的(不能从 class 中“删除”接口 - 你只能重新实现它)这意味着如果你不想子 class UserManager<TUser> 那么你将不能使用 subclass UserStoreBase<> 作为你重新实现 IUserStore<> 的基础 - 你必须从头开始,基本上。
    • (至少在我看来,这意味着 ASP.NET Core Identity 的默认组合 UserManagerUserStoreBase<...> 是一个糟糕的 OOP 设计,因为它需要实现来主动通过很多努力正确地 支持某些东西,而不是让一切都变得 opt-in.
    • Hey kids, inheritance is bad, mmm'key(好吧,不是“坏”,但至少如此充满问题应该避免。
      • Subclass 继承是一种生硬的工具,尤其是在 C# 和 Java 中,不可能将类型的“接口”1 与实现分开,并且无法在中描述类型的接口类型代数方式 - 所以我们不能定义子class是父class Base : ISomeInterfaceclass Derived使得class Derived不再实现ISomeInterface(我们能做的最好的事情就是滥用隐式转换为单独的类型,或者使用[EditorBrowsable]“隐藏”成员并使用显式重新实现接口throw new NotSupportedException(),这太可怕了,但即使是 Microsoft 在 .NET 的基础库中的某些地方也这样做了,例如 StreamTextWriter subclasses).
      • (此外,不要(滥用)使用继承只是为了在不同类型中拥有“共同成员”。我同意 C#/.NET 仍然很糟糕不支持 mixin,但是在 long-term 中,复制+粘贴转发器属性和方法的苦差事比处理不当使用继承的后果要容易得多。

1:我所说的“接口”不是指 interface 类型;我的意思是 classstructpublic 成员集,即类型的暴露表面。


(在我的 post 的早期编辑中,我建议 IConfigureOptions<LockoutOptions> 可用于配置 SupportsUserLockout,但我错了:因为没有完全禁用的选项锁定系统,但是如果你要 subclass both LockoutOptions 添加一个 bool Enabled 属性 and subclass UserManager<TUser>override bool SupportsUserLockout 指定为 return LockoutOptions.Enabled理想情况下,来自不可变副本,而不是原始可变选项对象 )然后那行得通。