custom asp.net identity store - why is HttpContext.Current empty at times

北城以北 提交于 2020-01-24 12:05:16

问题


I've implemented a custom User Store for ASP.NET Identity by following the example set here. That all works fine, except for this:

I need access to data about the currently logged in user in my user store. Normally, you'd access that by accessing

HttpContext.Current.User

Now, once auser has logged in, if he user then goes to the Manage controller (e.g. to try and change his/her password), when ASP.NET identity looks up the user again by calling

CustomUserManager.FindByIdAsync(string userId)

HttpContext.Current is empty altogether (that's prior to rendering the page). So, how do I get information about the HttpContext in this scenario? The user is properly logged in, so how do I figure out which user has been logged in?

@edit.. the problem is in CustomUserStore.. here's a bit of it

   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
}

and it's in the FindByAsync method where HttpContext.Current can be empty.

It happens in the Index method of the AccountController when the model is created

   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)
        };

And it's the FindById request in the HasPassword method that causes the problem

private bool HasPassword()
    {
        var user = UserManager.FindById(User.Identity.GetUserId());
        if (user != null)
        {
            return user.PasswordHash != null;
        }
        return false;
    }

The other 4 requests to the user manager all have a filled out HttpContext.Current. So it appears that it's calls to UserManager that cause the issue.


回答1:


Having identified the exact source of the problem, it's easy enough to fix.

Add this async emthod to check if the user has a password:

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

And in the Index method, use the new async methode

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)
    };

But, why does the synchronous method call break things? You'd imagine the sync call would run into the standard context where HttpContext.Current should be available.

I have a more custom User Store in my real project where I run into this problem a lot more frequently.. guess I need to check if contains a lot more synchronous access to UserManager methods.



来源:https://stackoverflow.com/questions/45502408/custom-asp-net-identity-store-why-is-httpcontext-current-empty-at-times

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!