UserManager.IsEmailConfirmedAsync(user.Id) is returning false - asp.net

I am working on the ForgotPassword section of my site. When I test it I have a breakpoint in the function and I can see that this line of code is returning false:
(await UserManager.IsEmailConfirmedAsync(user.Id)))
I have verified that EmailConfirmed field in the AspNetUsers table is set to True. Why would this still be returning false?
Here is the first part of the Account Controller where it initializes the UserManager:
[Authorize]
public class AccountController : Controller
{
private ApplicationSignInManager _signInManager;
private ApplicationUserManager _userManager;
public AccountController()
{
}
public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager )
{
UserManager = userManager;
SignInManager = signInManager;
}
public ApplicationSignInManager SignInManager
{
get
{
return _signInManager ?? HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
}
private set
{
_signInManager = value;
}
}
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
Found the requested Owin string in my Startup.Auth.cs class:
public partial class Startup
{
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);

You are likely pointing to the wrong database. The default templates for an MVC project with Identity will have code like this in the context:
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
This is then used by OwinContext as the method to create your context, and as such means that it will take the connection string from your web.config file called DefaultConnection. So you have 2 choices:
Fix the connection string to point to the correct database.
<add name="DefaultConnection"
connectionString="correct details here"
providerName="System.Data.SqlClient" />
Change the create method to return the context with a specific connection string:
public static ApplicationDbContext Create()
{
return new ApplicationDbContext("NameOfConnectionStringHere");
}

It seems await UserManager.IsEmailConfirmedAsync(user.Id)) always returns false when EmailConfirmed is set to False in AspNetUsers SQL table.

Related

UserManager.GetUserAsync without tracking changes?

I'm using the following function to check whether the person that wants to access some database record is an owner of this record:
public class AccessGuard
{
public async Task<bool> IsOwnerOrHaveRightsAsync(UserManager<ApplicationUser> userManager, ApplicationUser claimant, ClaimsPrincipal User)
{
ApplicationUser fullUser = await userManager.GetUserAsync(User);
if (claimant.Id == fullUser.Id)
{
return true;
}
return false;
}
}
It works, but as I've noticed: ApplicationUser is now added to ChangeTracker. What it means is I cannot call userManager.GetUserAsync later in code, because I get this error:
The instance of entity type 'ApplicationUser' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.
I usually use .AsNoTracking() while accessing database records, but there is nothing like that in userManager. How would you solve this?
I am using it in MVC Controller method as follows:
if (!await new AccessGuard().IsOwnerOrHaveRightsAsync(_userManager, Post.Author, User))
{
return Unauthorized();
}
You cannot use .AsNoTracking() with await userManager.GetUserAsync(User);. Alternatively you can do as follows:
public class AccessGuard
{
private readonly ApplicationDbContext _context;
private readonly IHttpContextAccessor _httpContextAccessor;
public AccessGuard(ApplicationDbContext context, IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
_context = context;
}
public async Task<bool> IsOwnerOrHaveRightsAsync(UserManager<ApplicationUser> userManager, ApplicationUser claimant, ClaimsPrincipal User)
{
var loggedInUserId = _httpContextAccessor.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
ApplicationUser fullUser = _context.ApplicationUsers.AsNoTracking()
.FirstOrDefaultAsync(au => au.Id == loggedInUserId);
if (claimant.Id == fullUser.Id)
{
return true;
}
return false;
}
}
Then you should register IHttpContextAccessor in the Startup class as follows:
public void ConfigureServices(IServiceCollection services)
{
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
// Or you can also register as follows
services.AddHttpContextAccessor();
}
Then to access AccessGuard service in your MVC controller method, first register AccessGuard in Startup as follows:
services.AddScoped<AccessGuard>();
Then in your controller method:
public IActionResult Index()
{
AccessGuard accessGuardService = (AccessGuard) HttpContext.RequestServices.GetService(typeof(AccessGuard));
// Now call `accessGuardService` service method here
return View();
}
You can also get AccessGuard service as follows:
AccessGuard accessGuardService = HttpContext.RequestServices.GetService<AccessGuard>();
and it requires namespace using Microsoft.Extensions.DependencyInjection;

Asp.Core Depenency Injection Session Null

I have a Asp.Core project with dependency injection. The problem is that when I get an instance of a CustomerService my session is null. But I pass it through with dependency injection.
My Controller looks like this:
private ISessionService _sessionService;
private IContainer _container;
public AuthController(ISessionService sessionService, IContainer container) {
_container = container;
_sessionService = sessionService;
// here my session is NOT NULL
string userName = _sessionService.Username;
}
public IActionResult Index() {
// here I have some code so the line below is not always needeed and therefore not injected in the constructor
IUserService userService = _container.GetInstance<IUserService>();
// here my session is NULL
string name = userService.GetUserName();
}
public class UserService : IUserService {
private ISessionService _sessionService;
private IHttpContextAccessor _httpContextAccessor;
public UserService(ISessionService sessionSerivce, IHttpContextAccessor httpContextAccessor) {
_sessionService = sessionSerivce;
_httpContextAccessor = httpContextAccessor;
}
public string GetUserName() {
return _sessionService.User.Name;
}
}
my StartUp.cs where I'm using StructureMap
Container container = new Container(expr => {
expr.For<IHttpContextAccessor>().Use<HttpContextAccessor>();
expr.For<ISessionService>().Use<SessionService>();
expr.For<IUserService>().Use<UserService>();
});
So why is my session null when I instantiate a UserService object when using the container class ?
UPDATE
I know now that the Session object is null because the life cycle of a MVC page. In my BaseController class I created a method named InitContainer like this:
public void InitContainer(Type typeOfInterface, Type typeOfClass) {
Configure(expr =>
For(typeOfInterface).Use(typeOfClass)
.Ctor<ISessionService>().Is(_sessionService)
.Ctor<IHttpContextAccessor>().Is(_httpContextAccessor)
);
}
}
When I want to use an instance of a service than I do this in my Controller method:
public IActionResult Test() {
InitContainer(typeof(ICustomerService), typeof(CustomerService));
ICustomerService customerService = _container.GetInstance<ICustomerService>();
}
I don't know if it's ugly or the right way to do this, but it works for me now.
Has someone a better way to do this?

Asp.net Identity DbContext / Repository Issue

I am using Asp.Net identity within my MVC app. I can see that this has it's own ApplicationDbContext - albeit it is connected to the same SQL db as my own DbContext I am using elsewhere.
So I am trying to access some of my own data via my own code within the AccountController - it does not seem to work I presume because of some confusion over which DBContext it thinks is active?
My Code :
public class AccountController : Controller
{
private ApplicationSignInManager _signInManager;
private ApplicationUserManager _userManager;
private PostageManager postmgr;
public AccountController()
{
}
public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager, PostageManager _postmgr)
{
UserManager = userManager;
SignInManager = signInManager;
postmgr = _postmgr;
}
public ApplicationSignInManager SignInManager
{
get
{
return _signInManager ?? HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
}
private set
{
_signInManager = value;
}
}
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
// GET: /Account/Register
[AllowAnonymous]
public ActionResult Register()
{
//create select list items for countries drop down
List<SelectListItem> countries;
countries = postmgr.GetCountries().Select(item => new SelectListItem
{
Value = item.Country,
Text = item.Country
}).ToList();
countries.Insert(0, new SelectListItem { Value = string.Empty, Text = "Select delivery country or region...", Selected = true });
RegisterViewModel mode = new RegisterViewModel
{
Countries = countries
};
return View();
}
}
}
PostageManager is just a class that sits over my DAL to fetch some data (which uses repository pattern) - I'm using just a kind of pass through method to grab a list of countries, and using it in exactly the same way I have in other controllers which works fine. Underneath that class is my repository code that is linked to my default connection string (DBContext). It's balking at the following line with a null reference exception, I think postmgr is null :
countries = postmgr.GetCountries().Select(item => new SelectListItem
In reverse to get access to the identity data within my own controllers I have done the following :
public BasketController(BasketManager _mgr, PostageManager _postmgr, ProductManager _prodmgr)
{
mgr = _mgr;
postmgr = _postmgr;
prodmgr = _prodmgr;
shopper = Cart.GetShopperId();
this.applicationDbContext = new ApplicationDbContext();
this.userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(this.applicationDbContext));
}
protected ApplicationDbContext applicationDbContext { get; set; }
protected UserManager<ApplicationUser> userManager { get; set; }
Which as far as I understand it points the identity code to use the right DbContext - I looked at doing this in reverse in my AccountController but can't fathom it out.
I basically just want to be able to use my own code that grabs my own data from within the Identity controllers to help pass extra data etc through to the views.
I might be wrong but most probably postmgr field is not initialized from constructor and that is why you have this error.
Explanation:
By default Asp will try to create controller instance by constructor without parameters. If Asp can't find constructor without parameters it will try to call constructor with parameters, but to make it possible you have to configure IoC in your app. As your controler has constructor without parameters it will be selected by Asp. So all 3 fields are empty.
But in properties SignInManager and UserManager you try to take value from field or from OwinContext. As field is empty your code will take value from OwinContext. OwinContext is quite complex and smart tool that create its context automatically based on configuration provided in Startup.Auth.cs file or any other file under App_Start folder.
I think I have figured it out - added the following to my NinjectControllerFactory :
ninjectKernel.Bind<IAuthenticationManager>().ToMethod(c => HttpContext.Current.GetOwinContext().Authentication); //.InRequestScope();
ninjectKernel.Bind<IUserStore<ApplicationUser>>().To<UserStore<ApplicationUser>>();
ninjectKernel.Bind<UserManager<ApplicationUser>>().ToSelf();
ninjectKernel.Bind<IRoleStore<IdentityRole, string>>().To<RoleStore<IdentityRole, string, IdentityUserRole>>();
ninjectKernel.Bind<RoleManager<IdentityRole>>().ToSelf();
And changed my constructor to :
public AccountController(PostageManager _postmgr)
{
postmgr = _postmgr;
}

Use WFC service calls as UserStore for ASP.NET Identity

I am creating a web forms application that uses a WCF service to interact with the database and other applications. This web forms application has no access to the database.
I would like to use ASP.Net Identity for user management. I have already created a custom UserStore and RoleStore by following this tutorial, Overview of Custom Storage Providers for ASP.NET Identity, as shown below.
public class UserStore : IUserStore<IdentityUser, long>, IUserRoleStore<IdentityUser, long>
{
UserServiceClient userServiceClient = new UserServiceClient();
public Task CreateAsync(IdentityUser user)
{
string userName = HttpContext.Current.User.Identity.GetUserName();
Genders gender = (Genders)user.CoreUser.Gender.GenderId;
UserDto userDto = userServiceClient.CreateUser(user.CoreUser.FirstName, user.CoreUser.LastName, gender, user.CoreUser.EmailAddress, user.CoreUser.Username, userName, user.CoreUser.Msisdn);
return Task.FromResult<UserDto>(userDto);
}
public Task DeleteAsync(IdentityUser user)
{
bool success = userServiceClient.DeactivateUser(user.CoreUser.UserId, "");
return Task.FromResult<bool>(success);
}
public Task<IdentityUser> FindByIdAsync(long userId)
{
UserDto userDto = userServiceClient.GetUserByUserId(userId);
return Task.FromResult<IdentityUser>(new IdentityUser { CoreUser = userDto, UserName = userDto.Username });
}
public Task<IdentityUser> FindByNameAsync(string userName)
{
UserDto userDto = userServiceClient.GetUserByUsername(userName);
return Task.FromResult<IdentityUser>(new IdentityUser { CoreUser = userDto, UserName = userDto.Username });
}
public Task UpdateAsync(IdentityUser user)
{
Genders gender = (Genders)user.CoreUser.Gender.GenderId;
UserDto userDto = userServiceClient.UpdateUserDetails(user.CoreUser.UserId, user.CoreUser.FirstName, user.CoreUser.LastName, gender, user.CoreUser.EmailAddress, user.CoreUser.Msisdn, "");
return Task.FromResult<UserDto>(userDto);
}
public void Dispose()
{
throw new NotImplementedException();
}
public Task AddToRoleAsync(IdentityUser user, string roleName)
{
throw new NotImplementedException();
}
public Task<IList<string>> GetRolesAsync(IdentityUser user)
{
List<UserRoleDto> roles = userServiceClient.GetUserRoles(user.Id);
return Task.FromResult<IList<string>>(roles.Select(r => r.Role.RoleName).ToList());
}
public Task<bool> IsInRoleAsync(IdentityUser user, string roleName)
{
throw new NotImplementedException();
}
public Task RemoveFromRoleAsync(IdentityUser user, string roleName)
{
throw new NotImplementedException();
}
}
That is the UserStore. Now the issue is implementing this for Identity.
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
In the class above that comes predefined with the template, there's the line:
app.CreatePerOwinContext(ApplicationDbContext.Create);
Now I don not have an ApplicationDbContext since this is handled in the WCF. Also, in the IdentityConfig class in the App_Start folder, there's the method Create that has this line,
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
Again, i have no idea with what to replace the ApplicationDbContext. Am I doing this right? Is the tutorial I followed sufficient to help me with what I need?
I used this link, ASP.NET Identity 2.0 Extending Identity Models and Using Integer Keys Instead of Strings
The issue was more about the fact that my user id was an long instead of the default string. I also did not need to pass the context as my UserStore did not expect a context in it's constructor

ASP.NET WebAPI Identity 2 - Error with GetOwinContext on user registration /Register method

I have a WebAPI 2.1 application and I am having a problem with User Registration. I placed a breakpoint on the first line of the Register method but it is not reached. Instead it fails in the area below:
public ApplicationUserManager UserManager
{
get
{
var a = Request; // this is null !!
return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
[AllowAnonymous]
[Route("Register")]
[ValidateModel]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
var user = new ApplicationUser() { // <<<<< Debug breakpoint here never reached
Email = model.Email,
FirstName = model.FirstName,
LastName = model.LastName,
OrganizationId = 1,
OrganizationIds = "1",
RoleId = (int)ERole.Student,
SubjectId = 1,
SubjectIds = "1",
UserName = model.UserName
};
System.ArgumentNullException was unhandled by user code
HResult=-2147467261
Message=Value cannot be null.
Parameter name: request
Source=System.Web.Http.Owin
ParamName=request
StackTrace:
at System.Net.Http.OwinHttpRequestMessageExtensions.GetOwinContext(HttpRequestMessage request)
at WebRole.Controllers.AccountController.get_UserManager() in c:\G\abr\WebRole\Controllers\Web API - Data\AccountController.cs:line 50
at WebRole.Controllers.AccountController.Dispose(Boolean disposing) in c:\G\ab\WebRole\Controllers\Web API - Data\AccountController.cs:line 376
at System.Web.Http.ApiController.Dispose()
at System.Web.Http.Cors.AttributeBasedPolicyProviderFactory.SelectAction(HttpRequestMessage request, IHttpRouteData routeData, HttpConfiguration config)
at System.Web.Http.Cors.AttributeBasedPolicyProviderFactory.GetCorsPolicyProvider(HttpRequestMessage request)
InnerException:
If anyone could give me any advice on where I could look to help solve this problem I would much appreciate it.
In particular can some explain to me the flow of how a request is handled in this configuration. I find it pretty confusing and I would like to know how the WebAPI and Owin fit together. Not knowing this is making it me difficult for me to understand the problem.
Thanks.
For reference here is my WebAPI start up class:
public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
}
}
Update 1 - question correct after Darin's comments. The problem is not in the constructor.
Update 2 - Dispose Method:
protected override void Dispose(bool disposing)
{
if (disposing)
{
UserManager.Dispose();
}
base.Dispose(disposing);
}
Update 3 - Added the /Register method to show where I have a breakpoint (that's never reached)
There is no check for a null _userManager in your dispose method but the backing field can still be null. Also you access the UserManager property instead of using the backing field directly. So every time _userManager is null and the AccountController gets disposed the UserManager will try to create a new OwinContext. And that will fail.
Change your dispose method to:
protected override void Dispose(bool disposing)
{
if (disposing && _userManager != null)
{
_userManager.Dispose();
_userManager = null
}
base.Dispose(disposing);
}
The problem I have is in the Account constructor
The HTTP Context is not available in a controller constructor and this is by design. The earliest point in the execution where you can access it is after the Initialize method:
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
// This is the earliest stage where you can access the HTTP context (request, response, ...).
}

Resources