【问题标题】:CreateUserIdenityAsync returns "UserId not found" exception for custom IdentityUserCreateUserIdenityAsync 为自定义 IdentityUser 返回“找不到用户 ID”异常
【发布时间】:2016-04-29 01:05:40
【问题描述】:

我正在关注bitoftech tutorial 关于使用 JWT 创建基于身份和角色的声明。我的应用程序用户是具有 int PK 的自定义用户表。

目前,GenerateUserIdentityAsync 方法只返回一个奇怪的UserId not found 错误。这是我的代码:

ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, "JWT");

以及User实体中的实现:

public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<User, int> manager, string authenticationType)
{
    //error on this line: CreateIdentityAsync throws error
    var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
    return userIdentity;
}

我的 UserManager 类是这样定义的:

public class AppUserManager : UserManager<User, int>

奇怪的是,当我调试时,GenerateIdentityAsync 中的实例 this 确实有一个 UserId 属性,但基础只有一个 id,我想知道这是不是它出错的地方? (听起来不对)

我正在查看source code(第 80 行),但我无法弄清楚异常是在哪里引发的。

抛出的确切异常是:

 UserId not found. 
 Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: 
    System.InvalidOperationException: 
    UserId not found.

stack trace 对我来说并不是那么有帮助

如何找出用户 ID 不可用的原因/位置?


模式详情:

我的GrantResourceOwnerCredentials()

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
    context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] {"*"});

    var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
    User user = await userManager.FindAsync(context.UserName, context.Password);

    if (user == null) // this is NOT null
    {
        context.SetError("invalid_grant", "The username or password is incorrect");
        return;
    }

    // this line fails
    ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, "JWT"); 
    var ticket = new AuthenticationTicket(oAuthIdentity, null);
    context.Validated(ticket);
}

还有ApplicationUser(在我的例子中,就是User

public partial class User : IdentityUser<int, CustomUserLogin, CustomUserRole, CustomUserClaim>
{  
    public int UserId { get; set; }
    public string Fullname { get; set; }
    public string Address { get; set; }
    public string ContactNumber { get; set; }
}

【问题讨论】:

  • 在你的 aspnet 数据库中验证你是否有正确的列名(UserId 而不是 Id,反之亦然)。还有一种可能性是列类型不匹配(与 nvarchar(256) 相比的唯一标识符)。

标签: c# asp.net asp.net-web-api asp.net-identity


【解决方案1】:

正如您在调试时发现的那样,IdentityUser 有一个 Id,在您的情况下它将代表用户的 ID。

您需要从User 类中删除UserId,使用IdentityUser 中的基本Id,并将自定义用户表中的UserId 列重命名为Id

User 类中的任何属性也需要在数据库的用户表中具有匹配的列。如果不是,那么对于不匹配的属性,您将收到相同的错误。

这意味着FullnameAddressContactNumber 必须在AspNetUsers 表中具有匹配的列名,否则这些属性也会出现相同的错误。

【讨论】:

  • 嗨,在我的中进行了这些更改,但仍然遇到相同的错误;我现在质疑UserId 是否是我认为的那样,没有内部异常,只有堆栈跟踪,但不幸的是,这并没有太大帮助。您上面的代码两次拉取用户,如果它有效,这不是问题,我可以稍后重构,但它仍然抛出完全相同的异常
  • @LocustHorde,我回到绘图板并重新检查了您的问题。使用您提供的其他信息,我能够重新创建相同的异常,包括内部异常。 UserId 必须是 AspNetUsers 表中的有效列。我认为之前的评论者也指出了这一点。
  • 太棒了!在您发表评论后,我注意到表格中有两个UserIdId 列,在我的种子方法中,我只是填充UserId,而Id 为零。当我尝试登录时,无论出于何种原因,找不到不断抛出UserId 的方法。一旦我手动将零更改为整数,它就可以正常工作了!所以我想我必须删除 Id 并以某种方式告诉 Identity 使用 UserId 代替......
  • 哎呀,刚刚看到你的编辑,让我跟进,谢谢!
  • @LocustHorde 那是正确的。我也会检查并更新我的答案。您是先编写代码还是连接到现有表?
【解决方案2】:

User 类中同时具有 UserIdId 属性 - Id 继承自 IdentityUser。问题是您可能将UserId 配置为User 的主键。

你得到的异常是在ClaimsIdentityFactory.CreateAsync 方法中抛出的,在line 97 UserManager.GetSecurityStampAsync 上。如您所见,user.Id 用于检索安全标记。

如果您查看UserManager.GetSecurityStampAsync 内部,您会看到您得到的异常正是在这里抛出的:

public virtual async Task<string> GetSecurityStampAsync(TKey userId)
{
    ThrowIfDisposed();
    var securityStore = GetSecurityStore();
    var user = await FindByIdAsync(userId).WithCurrentCulture();
    if (user == null)
    {
        throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Resources.UserIdNotFound,
            userId));
    }
    return await securityStore.GetSecurityStampAsync(user).WithCurrentCulture();
}

因此,从User 类中删除UserId 属性并开始使用Id(继承自IdentityUser)代替。

【讨论】:

    【解决方案3】:

    我遇到了完全相同的问题。经过一番头疼后,我可以解决真正的问题。 当您将 User 类的 Id 属性的数据类型更改为字符串时,Guid().ToString() 将分配给构造函数中的 Id 属性,并将相同的值保存到数据库中,并且 Identity 使用该值检索用户详细信息.

    但是,如果您将 Id 属性的数据类型更改为 int 并且没有在构造函数中为该属性提供值,则 Identity 仍会尝试使用默认的 int 值 (0) 来检索用户详细信息,这会导致抛出消息“System.InvalidOperationException: UserId not found”。

    我通过 command.ExecuteScalar() 从数据库中检索值并将该值分配给 user.Id 解决了这个问题。 希望这对面临类似问题的人有所帮助。

    【讨论】:

    • 嗨@vkuttyp,你在说什么构造函数?谢谢。
    • 你能分享更多细节吗?你到底在哪里设置了 user.Id ?谢谢
    • 嗨@chemitaxis,我提到的构造函数是IdentityUser类构造函数。
    • 嗨。我面临的实际问题与问题无关。我的问题来自创建新用户。所以我所做的就是在将新用户插入数据库后从数据库中检索主键并将其更新为用户对象。
    【解决方案4】:

    您的 ApplicationUser 类是什么样的? 这种方法在您的应用程序中是什么样的?

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context){}
    

    Taiseer 关于 GrantResourceOwnerCredentials 的 cmets 是:

    "我们正在为登录用户建立一个身份,这个身份 将包含经过身份验证的用户的所有角色和声明”

    我必须将 ClaimTypes.NameIdentifier 添加到 ClaimsIdentity 以解决类似问题。这是我的 GrantResourceOwnerCredentials 方法的重要部分:

    ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
    
    if (user == null)
    {
        context.SetError("invalid_grant", "The user name or password is incorrect.");
        return;
    }
    
    var identity = new ClaimsIdentity(context.Options.AuthenticationType);
    identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()));
    

    【讨论】:

    • 嗨,添加了上面的两个代码块;你没有使用 JWT?
    • 我用DefaultAuthenticationTypes.ApplicationCookie试过了,还是一样的错误,我想我至少现在可以排除JWT干扰它
    • 正确,我没有使用 JWT。
    【解决方案5】:

    就我而言,发生此错误是因为我在 Account Controller 的方法 Login 中添加了另一个 SignInManager(以下是添加角色的示例)。它在同一个方法中执行 SignInManager.PasswordSignInAsync 和 SignInManager.SignInAsync 并在 ApplicationUser 中调用 GenerateUserIdentityAsync(...) 两次,第一次成功,第二次给了我异常“UserId”Not Found。

    【讨论】:

      【解决方案6】:

      服务器=xxxx;初始目录=xxxx;;用户 ID=xxxx_user;密码=xxxx;其中用户 id 有一个空格,而不是 服务器=xxxx;初始目录=xxxx;;用户ID=xxxx_user;密码=xxxx;错误的!!!!!!! 请参阅https://www.connectionstrings.com/sql-azure/ 进行确认。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-22
        • 2015-01-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多