IUserStore< TUser>.CreateAsync:如何在自定义实现中指示失败

本文关键字:自定义 实现 失败 指示 TUser CreateAsync IUserStore | 更新日期: 2023-09-27 18:15:56

我正在为IUserStore编写一个自定义实现。create方法的签名是:

public async virtual Task CreateAsync(TUser user)

考虑到Microsoft.AspNet.Identity的核心接口IUserStore是(这是相同的),这是有意义的。

然而,在Microsoft.AspNet.Identity中定义的UserManager类的接口是:

public virtual Task<IdentityResult> CreateAsync(TUser user);

我的问题是我不知道我应该如何将这个IdentityResult传递给UserManager,因为在商店中的返回类型只是"任务"。我有一个自定义逻辑来确定是否可以创建一个用户,所以我真的需要告诉UserManager CreateAsync的结果。

IUserStore< TUser>.CreateAsync:如何在自定义实现中指示失败

查看UserManager.CreateAsync的源代码(这是Identity 2.0),您可以看到在调用IUserStore.CreateAsync之前,它会调用IIdentityValidator<TUser>.ValidateAsync,它负责实际返回相关的IdentityResult对象:

public virtual async Task<IdentityResult> CreateAsync(TUser user)
{
        ThrowIfDisposed();
        await UpdateSecurityStampInternal(user).ConfigureAwait(false);
        var result = await UserValidator.ValidateAsync(user).ConfigureAwait(false);
        if (!result.Succeeded)
        {
            return result;
        }
        if (UserLockoutEnabledByDefault && SupportsUserLockout)
        {
            await GetUserLockoutStore().SetLockoutEnabledAsync(user, true).ConfigureAwait(false);
        }
        await Store.CreateAsync(user).ConfigureAwait(false);
        return IdentityResult.Success;
}

IUserStore.CreateAsync的主要目的是调用保存数据的底层数据源。似乎你实际上想要实现IIdentityValidator<TUser>并将其设置在你的UserManager实例上。

答案在源代码中,这是在撰写本文时UserManager中实现的一部分:

public virtual async Task<IdentityResult> CreateAsync(TUser user,
        CancellationToken cancellationToken = default(CancellationToken))
    {
        ThrowIfDisposed();
        await UpdateSecurityStampInternal(user, cancellationToken);
        var result = await ValidateUserInternal(user, cancellationToken);
        if (!result.Succeeded)
        {
            return result;
        }
        if (Options.Lockout.EnabledByDefault && SupportsUserLockout)
        {
            await GetUserLockoutStore().SetLockoutEnabledAsync(user, true, cancellationToken);
        }
        await UpdateNormalizedUserNameAsync(user, cancellationToken);
        await Store.CreateAsync(user, cancellationToken);
        return IdentityResult.Success;
    }

基本上它们总是返回true。这意味着在当前版本中,将我的创建检查放在UserStore中违背了框架的预期用途。

然而,我已经注意到这将在下一个版本中改变。IUserStore接口将变成:

Task<IdentityResult> CreateAsync(TUser user, CancellationToken cancellationToken);

和UserManager的实现:

public virtual async Task<IdentityResult> CreateAsync(TUser user)
    {
        ThrowIfDisposed();
        await UpdateSecurityStampInternal(user);
        var result = await ValidateUserInternal(user);
        if (!result.Succeeded)
        {
            return result;
        }
        if (Options.Lockout.AllowedForNewUsers && SupportsUserLockout)
        {
            await GetUserLockoutStore().SetLockoutEnabledAsync(user, true, CancellationToken);
        }
        await UpdateNormalizedUserNameAsync(user);
        await UpdateNormalizedEmailAsync(user);
        return await Store.CreateAsync(user, CancellationToken);
    }

因此,将创建逻辑放在UserStore中是可能的。在我看来,这将是一种更好的设计方式,因为客户端不应该处理完整性问题。