我按照此处设置的示例为 ASP.NET 身份实现了自定义用户存储。一切正常,除了这个:
我需要访问有关用户存储中当前登录用户的数据。通常,您可以通过访问来访问它
HttpContext.Current.User
现在,一旦用户登录,如果该用户随后转到管理控制器(例如尝试更改他/她的密码(,则当 ASP.NET 身份通过调用再次查找用户时
CustomUserManager.FindByIdAsync(string userId)
HttpContext.Current 完全是空的(这是在呈现页面之前(。那么,在这种情况下,如何获取有关 HttpContext 的信息?用户已正确登录,那么如何确定哪个用户已登录?
@edit..问题出在CustomUserStore中..这里有一点
public class CustomUserStore<TUser> : IUserStore<TUser>, IUserLoginStore<TUser>, IUserClaimStore<TUser>, IUserPasswordStore<TUser>, IUserSecurityStampStore<TUser>, IUserEmailStore<TUser>, IUserPhoneNumberStore<TUser>,
IUserLockoutStore<TUser, string>, IUserTwoFactorStore<TUser, string>//, IQueryableUserStore<TUser>
where TUser: CustomUser<string>, IUser<string>
{
string storageFile = @"c:tempaspnetusers.json";
List<TUser> users;
public CustomUserStore()
{
if (File.Exists(storageFile))
{
string contents = File.ReadAllText(storageFile);
users = JsonConvert.DeserializeObject<List<TUser>>(contents);
if (users == null)
users = new List<TUser>();
}
else
users = new List<TUser>();
}
#region IUserStore implementation
public Task<TUser> FindByIdAsync(string userId)
{
string sessionId = HttpContext.Current?.Session?.SessionID;
return Task.FromResult<TUser>(users.FirstOrDefault(u => u.Id == userId));
}
public Task<TUser> FindByNameAsync(string userName)
{
string sessionId = HttpContext.Current?.Session?.SessionID;
return Task.FromResult<TUser>(users.FirstOrDefault(u => string.Compare(u.UserName, userName, true) == 0));
}
#endregion
}
它在 FindByAsync 方法中,其中 HttpContext.Current 可以为空。
创建模型时,它发生在帐户控制器的索引方法中
var model = new IndexViewModel
{
HasPassword = HasPassword(),
PhoneNumber = await UserManager.GetPhoneNumberAsync(userId),
TwoFactor = await UserManager.GetTwoFactorEnabledAsync(userId),
Logins = await UserManager.GetLoginsAsync(userId),
BrowserRemembered = await AuthenticationManager.TwoFactorBrowserRememberedAsync(userId)
};
正是HasPassword 方法中的 FindById 请求导致了问题
private bool HasPassword()
{
var user = UserManager.FindById(User.Identity.GetUserId());
if (user != null)
{
return user.PasswordHash != null;
}
return false;
}
对用户管理器的其他 4 个请求都填写了 HttpContext.Current。因此,似乎是对UserManager的调用导致了问题。
确定问题的确切来源后,很容易修复。
添加此异步 emthod 以检查用户是否有密码:
private async Task<bool> HasPasswordAsync()
{
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
if (user != null)
{
return user.PasswordHash != null;
}
return false;
}
在索引方法中,使用新的异步方法e
var model = new IndexViewModel
{
HasPassword = await HasPasswordAsync(),
PhoneNumber = await UserManager.GetPhoneNumberAsync(userId),
TwoFactor = await UserManager.GetTwoFactorEnabledAsync(userId),
Logins = await UserManager.GetLoginsAsync(userId),
BrowserRemembered = await AuthenticationManager.TwoFactorBrowserRememberedAsync(userId)
};
但是,为什么同步方法调用会破坏事情呢?您可以想象同步调用将运行在 HttpContext.Current 应该可用的标准上下文中。
我在我的实际项目中有一个更自定义的用户存储,我更频繁地遇到这个问题......猜我需要检查是否包含对 UserManager 方法的更多同步访问。