سؤال

I recently updated Asp.Net Identity Core of my application form 1.0 to 2.0.

There are new features which I wanted to try like GenerateEmailConfirmationToken, etc.

I'm using this project as a reference.

When the user tries to register, I get error during the execution of Post method of Register

private readonly UserManager<ApplicationUser> _userManager;     

public ActionResult Register(RegisterViewModel model)
{
    if (ModelState.IsValid)
    {
        var ifUserEXists = _userManager.FindByName(model.EmailId);
        if (ifUserEXists == null) return View(model);
        var confirmationToken = _userRepository.CreateConfirmationToken();//this is how i'm generating token currently.                
        var result = _userRepository.CreateUser(model,confirmationToken);
        var user = _userManager.FindByName(model.EmailId);
        if (result)
        {
            var code = _userManager.GenerateEmailConfirmationToken(user.Id);//error here
            _userRepository.SendEmailConfirmation(model.EmailId, model.FirstName, confirmationToken);
            //Information("An email is sent to your email address. Please follow the link to activate your account.");
            return View("~/Views/Account/Thank_You_For_Registering.cshtml");
        }     
    }
    
    //Error("Sorry! email address already exists. Please try again with different email id.");
    ModelState.AddModelError(string.Empty, Resource.AccountController_Register_Sorry__User_already_exists__please_try_again_);
    return View(model);
}

In the line

 var code = _userManager.GenerateEmailConfirmationToken(user.Id);

I get error saying:

No IUserTokenProvider is registered.

For now, I just wanted to see what kind of code it generates. Is there some change I need to make to my ApplicationUser class that inherits from IdentityUser class?

Or is there something I need to change to get those function work?

هل كانت مفيدة؟

المحلول

You have to specify a UserTokenProvider to generate a token.

using Microsoft.Owin.Security.DataProtection;
using Microsoft.AspNet.Identity.Owin;
// ...

var provider = new DpapiDataProtectionProvider("SampleAppName");

var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>());

userManager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(
    provider.Create("SampleTokenName"));

You should also read this article: Adding Two Factor Authentication to an Application Using ASP.NET Identity.

نصائح أخرى

In ASP.NET Core it's nowadays possible to configure a default service in the Startup.cs like this:

services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddDefaultTokenProviders();

There is no need to call the DpapiDataProtectionProvideror anything like that. The DefaultTokenProviders() will take care of the call to GenerateEmailConfirmationToken from the UserManager.

In addition to the accepted answer, I'd like to add that this approach will not work in Azure Web-Sites, you'd get CryptographicException instead of a token.

To get it fixed for Azure, implement your own IDataProtector: see this answer

Slightly more detail in blog-post

My solution :

    var provider = new DpapiDataProtectionProvider("YourAppName");
    UserManager.UserTokenProvider = new DataProtectorTokenProvider<User, string>(provider.Create("UserToken")) 
        as IUserTokenProvider<User, string>;

My problem with this code solved.
Good luck friends.

In case anyone else makes the same mistake that I did. I tried to make a function like the one below and sure enough the error "No IUserTokenProvider is registered." was gone. However as soon as I tried to use the link generated from "callbackUrl" I got the error "Invalid token." In order for it to work you need to get the HttpContext UserManager. If you are using a standard ASP.NET MVC 5 application with individual user accounts you can do it like below..

Code that works:

public ActionResult Index()
     {
         //Code to create ResetPassword URL
         var userManager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
         var user = userManager.FindByName("useremail@gmail.com");
         string code = userManager.GeneratePasswordResetToken(user.Id);
         var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
         return View();
     }

First try that does not work, No IUserTokenProvider is registered. is gone but the URL created gets Invalid token..

public ActionResult NotWorkingCode()
     {
             //DOES NOT WORK - When used the error "Invalid token." will always trigger.
             var provider = new DpapiDataProtectionProvider("ApplicationName");
             var userManager = new ApplicationUserManager(new UserStore<ApplicationUser>(new ApplicationDbContext()));
             userManager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(provider.Create("ASP.NET Identity"));
             var user = userManager.FindByName("useremail@gmail.com");
             string code = userManager.GeneratePasswordResetToken(user.Id);
             var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
             //DOES NOT WORK - When used the error "Invalid token." will always trigger.
         return View();
     }

As per pisker above

In startup.cs you can use

services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddDefaultTokenProviders();

In .net core 2.0 you may need to add to the startup.cs:

using Microsoft.AspNetCore.Identity;

This worked fine for me.

While modifying .NET Core's Identity files, I stumbled upon this error:

NotSupportedException: No IUserTwoFactorTokenProvider named 'Default' is registered.

The

Microsoft.AspNetCore.Identity.UserManager.GenerateUserTokenAsync

function couldn't generate a token because no provider was available upon registering a new user. This error has an easy fix though!

If you're like me, you changed AddDefaultIdentity in the Startup.cs file to AddIdentity. I wanted to implement my own user that inherited from the base user. By doing this I lost the default token providers. The fix was to add them back with AddDefaultTokenProviders().

        services.AddIdentity<User, UserRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

After that fix, everything worked again!

source: https://mattferderer.com/NotSupportedException-No-IUserTwoFactorTokenProvider-tuser-named-default-registered

I got the same error after updating Identity, and found that it was because I was using Unity.

See this question thread on the solution: Register IAuthenticationManager with Unity

Also below for quick reference:

Here is what I did to make Unity play nice with ASP.NET Identity 2.0:

I added the following to the RegisterTypes method in the UnityConfig class:

container.RegisterType<DbContext, ApplicationDbContext>(new HierarchicalLifetimeManager());
container.RegisterType<UserManager<ApplicationUser>>(new HierarchicalLifetimeManager());
container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(new HierarchicalLifetimeManager());
container.RegisterType<AccountController>(new InjectionConstructor());

You may also be intrested in looking here:
How to implement a TokenProvider in ASP.NET Identity 1.1 nightly build?
to use the default token provider implementation from Microsoft.Identity.Owin package

in IdentityConfig.cs, Add your twofactor option:

        manager.RegisterTwoFactorProvider("PhoneCode", new PhoneNumberTokenProvider<ApplicationUser>
        {
            MessageFormat = "Your security code is {0}"
        });
        manager.RegisterTwoFactorProvider("EmailCode", new EmailTokenProvider<ApplicationUser>
        {
            Subject = "Security Code",
            BodyFormat = "Your security code is {0}"
        });
        //config sms service 
        manager.SmsService = new Services.SMS();
        var dataProtectionProvider = options.DataProtectionProvider;
        if (dataProtectionProvider != null)
        {
            manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
        }

It can also be useful for ASP.NET Framework (with simple sync task):

using Microsoft.Owin.Security.DataProtection;
using Microsoft.Owin.Security;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
...

var userStore = new UserStore<IdentityUser>();
var userManager = new UserManager<IdentityUser>(userStore);
var user = userManager.FindByName(MyUserNameTextBox.Text);

var provider = new DpapiDataProtectionProvider(System.Web.Hosting.HostingEnvironment.ApplicationHost.GetSiteName());
userManager.UserTokenProvider = (IUserTokenProvider<IdentityUser, string>)(new DataProtectorTokenProvider<IdentityUser, string>(provider.Create("UserToken")) as IUserTokenProvider<IdentityUser, string>);

var token = userManager.GeneratePasswordResetToken(user.Id);
var result = userManager.ResetPassword(user.Id, token, MyPasswordTextBox.Text);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top