没有注册IUserTokenProvider

109
我最近将我的应用程序从1.0更新到了2.0的Asp.Net Identity Core版本。新版本有一些我想尝试的新功能,例如GenerateEmailConfirmationToken等。我参考了这个项目。当用户试图注册时,在注册的Post方法执行过程中出现了错误。
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类做一些更改吗? 或者说,我需要做一些更改以使这些函数正常工作吗?


1
有没有办法根据除了电子邮件地址以外的其他字段检查用户是否存在?例如,如果我有两个名为CustomerNumber和Postcode的字段,用于已经预先存在于数据库中的用户,以防止任何人注册。 - Jay
11个回答

134
你必须指定一个 UserTokenProvider 来生成令牌。
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"));

您还应阅读此文章:将双因素身份验证添加到使用ASP.NET Identity的应用程序中


5
“Sample” 和 “EmailConfirmation” 是什么?一些文本可以是任何内容吗? - Cybercop
2
"Sample"=应用名称,"EmailConfirmation"=目的(例如参数名称) - meziantou
5
可以,但是你需要使用相同的方法来生成和验证令牌。 - meziantou
1
链接没问题。你把这段代码放在初始化“UserManager”的地方。 - meziantou
这会导致在 .netcore 中无法从程序集加载类型 'System.Security.Cryptography.DpapiDataProtector'。 - TAHA SULTAN TEMURI
有点惊讶的是,5年后,asp.net core文档仍然没有提供任何有用的信息来指导您正确使用它... - Douglas Gaskell

37
在ASP.NET Core中,现在可以像下面这样在Startup.cs中配置默认服务:

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

不需要调用DpapiDataProtectionProvider或类似的内容。DefaultTokenProviders()会处理从UserManager调用GenerateEmailConfirmationToken的操作。


1
那一行代码节省了我2个小时的时间...谢谢。 - Eskander One

22

除了接受的答案外,我想补充一点,在Azure Web-Sites中,这种方法不起作用,你会得到CryptographicException而不是令牌。

要在Azure中解决此问题,请实现自己的IDataProtector:请参见此答案

更多细节请参考博客文章


16

我的解决方案:

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

我的代码问题已经解决。
祝好运,朋友们。


1
使用 Microsoft.Owin.Security.DataProtection; - Amin Ghaderi
我不得不在两个泛型中使用DataProtectorTokenProvider<IdentityUser, string>而不是<User, string>。此外,在GeneratePasswordResetToken中,userId是guid字符串Id,而不是userName或Email。 - Dan Randolph

9
如果其他人犯了和我一样的错误,以下是一个类似于我的函数。确实可以消除错误“No IUserTokenProvider is registered.”然而,一旦我尝试使用从“callbackUrl”生成的链接,我就会遇到错误“Invalid token.”为了让它工作,你需要获取HttpContext UserManager。如果你正在使用标准的ASP.NET MVC 5应用程序并且具有单独的用户帐户,可以像下面这样做。
代码演示:
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();
     }

第一次尝试不起作用,No IUserTokenProvider is registered.已经消失,但创建的URL得到了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();
     }

也在 Web API 控制器中工作过,只需要使用 HttpContext.Current.GetOwinContext() 即可。 - Gabe

6

根据上述pisker的说法,在startup.cs文件中,您可以使用以下内容:

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

在 .net core 2.0 中,您可能需要在 startup.cs 中添加以下内容:
using Microsoft.AspNetCore.Identity;

这对我来说很有效。

2
我认为重要的是记住这是一个Asp .NET Core解决方案,它将无法与Asp .NET Framework兼容。 - Machado

6
修改.NET Core身份文件时,我遇到了这个错误:

NotSupportedException: 没有名为'Default'的IUserTwoFactorTokenProvider被注册。

当注册一个新用户时,Microsoft.AspNetCore.Identity.UserManager.GenerateUserTokenAsync函数无法生成令牌,因为没有可用的提供程序。 然而,这个错误很容易解决!
如果您像我一样,在 Startup.cs 文件中更改了AddDefaultIdentityAddIdentity,那么您希望实现从基本用户继承的自己的用户。 这样做会丢失默认的令牌提供程序。 修复方法是使用AddDefaultTokenProviders()将它们添加回来。
        services.AddIdentity<User, UserRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

修复后,一切都正常工作了!

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


1

更新Identity后,我遇到了相同的错误,并发现是因为我正在使用Unity。

请查看以下解决方案的问题线程: Register IAuthenticationManager with Unity

此外,以下内容仅供快速参考:

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

1
我遵循了这个步骤,但它没有起作用(对于 GeneratePasswordResetToken -- 但仍然得到相同错误 "No IUserTokenProvider is registered")。在 UnityConfig.cs 中添加 container.RegisterType<ApplicationUserManager>( new InjectionFactory(c => HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>())); 之后,它就正常工作了。 - user5398447

0

0
在IdentityConfig.cs中,添加你的双因素选项:
        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"));
        }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接