自定义asp.net标识存储 - 为什么HttpContext.Current有时为空

时间:2017-08-04 08:56:58

标签: c# asp.net-mvc asp.net-identity httpcontext

我已按照示例集here实现了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:\temp\aspnetusers.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可以为空。

创建模型时,会在AccountController的Index方法中发生

   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导致问题。

1 个答案:

答案 0 :(得分:0)

确定问题的确切来源后,它很容易修复。

添加此async emthod以检查用户是否有密码:

private async Task<bool> HasPasswordAsync()
    {
        var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
        if (user != null)
        {
            return user.PasswordHash != null;
        }
        return false;
    }

在Index方法中,使用新的异步方法

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方法的同步访问。