我跟随bitoftech tutorial关于使用JWT创建基于身份和角色的声明。我的应用程序用户是一个带有int PK的自定义User表。
目前,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>
奇怪的是,当我调试时,this
中的实例GenerateIdentityAsync
确实有UserId
属性,但基数只有id
,我想知道是不是 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.
它出错的地方? (听起来不对)
我正在查看source code(第80行),但我无法确定抛出异常的位置。
抛出的确切异常是:
GrantResourceOwnerCredentials()
stack trace并非对我有用(
)如何找出UserId不可用的原因/位置?
模式详情:
我的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; }
}
)
_1
答案 0 :(得分:5)
正如您在调试IdentityUser
时发现的那样Id
,在您的情况下代表用户的ID。
您需要从UserId
课程中删除User
,使用Id
中的基础IdentityUser
并重命名自定义用户表格中的UserId
列到Id
。
您User
类中的任何属性都需要在数据库的用户表中包含匹配的列。如果没有,那么对于不匹配的属性,您将得到相同的错误。
这意味着Fullname
,Address
和ContactNumber
必须在AspNetUsers
表中具有匹配的列名,否则您也会为这些属性获得相同的错误。
答案 1 :(得分:3)
您的UserId
课程中Id
和User
属性都有Id
继承自IdentityUser
。问题是您可能已将UserId
配置为User
的主键。
ClaimsIdentityFactory.CreateAsync
UserManager.GetSecurityStampAsync
方法在[{3}} 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
(继承自// C#, all versions
private readonly int _foo;
public int Foo
{
get { return _foo; }
}
// C#, version 6+
// actually, this is the same as above, but backing field is generated
// for you by compiler
public int Foo { get; }
)。
答案 2 :(得分:2)
您的ApplicationUser类是什么样的? 这个方法在你的应用程序中是什么样的?
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context){}
Taiseer对GrantResourceOwnerCredentials的评论是:
&#34;我们正在为登录用户构建一个身份,即此身份 将包含经过身份验证的用户的所有角色和声明&#34;
我必须将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()));
答案 3 :(得分:2)
我遇到了完全相同的问题。经过一段时间的痛苦,我可以解决真正的问题。 当您将User类的Id属性的数据类型更改为string时,将Guid()。ToString()分配给构造函数中的Id属性,并将相同的值保存到数据库,Identity将使用该值检索用户详细信息。
但是,如果您将Id属性的数据类型更改为int并且未在构造函数中为该属性提供值,则Identity仍会尝试使用默认的int值(0)来检索用户详细信息抛出消息&#34; System.InvalidOperationException:找不到UserId&#34;。
我通过command.ExecuteScalar()从数据库中检索值来解决这个问题,并将值赋给user.Id. 希望这有助于某些人面临类似的问题。
答案 4 :(得分:0)
在我的情况下,发生此错误是因为我在帐户控制器的Login方法中添加了另一个SignInManager(以下是添加角色的示例)。它在同一方法中执行SignInManager.PasswordSignInAsync和SignInManager.SignInAsync,并两次在ApplicationUser中调用GenerateUserIdentityAsync(...),第一个成功,第二个给了我“ UserId”异常。
答案 5 :(得分:-1)
服务器= xxxx;初始目录= xxxx ;; 用户ID = xxxx_user;密码= xxxx;用户ID中有空格,而不是 服务器= xxxx;初始目录= xxxx ;; 用户ID = xxxx_user;密码= xxxx;错误!!!!!!! 参见https://www.connectionstrings.com/sql-azure/进行确认。