没有注册 IUserTokenProvider

我最近更新了我的申请表1.0到2.0的 Asp.Net Identity Core

有一些新的功能,我想尝试像 GenerateEmailConfirmationToken等。

我使用 这个项目作为参考。

当用户尝试注册时,在执行 Post 方法 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);
}

排队

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

如果我说:

No IUserTokenProvider is registered.

现在,我只想看看它会生成什么样的代码。 是否需要对从 IdentityUser类继承的 ApplicationUser类做一些更改?

或者我需要改变什么才能让这些功能正常工作?

51133 次浏览

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 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.

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

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

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

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.

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.

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

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

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