我正在按照bitoftech教程进行操作,了解如何使用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;
}
我的用户管理器类定义如下:
public class AppUserManager : UserManager<User, int>
奇怪的是,当我调试时,GenerateIdentityAsync
中this
的实例确实具有UserId
属性,但基只有一个id
,我想知道这是否是它出错的地方?(听起来不对)
我正在查看源代码(第 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.
堆栈跟踪并不是那么有用(对我来说)
如何找出用户 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; }
}
正如您在调试时发现的那样,IdentityUser
有一个Id
,在您的情况下,它将代表用户的 ID。
您需要从 User
类中删除UserId
,使用 IdentityUser
中的基Id
,并将自定义 User 表中的UserId
列重命名为 Id
。
User
类中的任何属性也需要在数据库的用户表中具有匹配的列。如果不是,则对于不匹配的属性,您将收到相同的错误。
这意味着Fullname
、Address
和 ContactNumber
必须在AspNetUsers
表中具有匹配的列名,否则这些属性也会收到相同的错误。
您的User
类中同时具有UserId
和Id
属性 - Id
继承自IdentityUser
。问题是您可能将UserId
配置为User
的主键。
您得到的异常在ClaimsIdentityFactory.CreateAsync
方法中引发,在第 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();
}
因此,从类中删除UserId
属性User
并开始使用Id
(继承自IdentityUser
)。
我遇到了完全相同的问题。经过长时间的头疼,我可以解决真正的问题。将 User 类的 Id 属性的数据类型更改为字符串时,Guid()。ToString() 被分配给构造函数中的 Id 属性,并将相同的值保存到数据库中,Identity 使用该值检索用户详细信息。
但是,如果将 Id 属性的数据类型更改为 int,并且未在构造函数中为该属性提供值,则标识仍会尝试使用默认的 int 值 (0) 检索用户详细信息,这会导致引发消息"System.InvalidOperationException: 找不到 UserId"。
我通过命令从数据库中检索值来解决此问题。ExecuteScalar() 并将值分配给 user.Id。希望这将帮助一些面临类似问题的人。
你的 ApplicationUser 类是什么样的?此方法在您的应用程序中是什么样的?
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context){}
Taiseer对GrantResourceOwnerCredentials的评论是:
"我们正在为登录用户构建一个身份,这个身份 将包含经过身份验证的用户的所有角色和声明"
我不得不将 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()));
就我而言,发生此错误是因为我在帐户控制器中的登录方法中添加了另一个 SignInManager(按照添加角色的示例)。它以相同的方法执行SignInManager.PasswordSignInAsync和SignInManager.SignInAsync,这在ApplicationUser中调用了GenerateUserIdentityAsync(...)两次,第一个成功了,第二个给了我异常"UserId"未找到。
服务器=xxxx;初始目录=xxxx;;用户 ID = xxxx_user;密码=xxxx; 其中用户 ID 中有一个空格,而不是服务器=xxxx;初始目录=xxxx;;用户 ID = xxxx_user;密码=xxxx; 错!!!!!!!请参阅 https://www.connectionstrings.com/sql-azure/进行确认。