Nenhum IUserTokenProvider está registrado

101

Recentemente atualizei Asp.Net Identity Core meu formulário de inscrição 1.0 para 2.0.

Existem novos recursos que eu gostaria de experimentar GenerateEmailConfirmationToken, etc.

Estou usando este projeto como referência.

Quando o usuário tenta se cadastrar, recebo um erro durante a execução do método Post de 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);
}

Na linha

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

Eu recebo um erro dizendo:

No IUserTokenProvider is registered.

Por enquanto, eu só queria ver que tipo de código ele gera. Há alguma mudança que preciso fazer em minha ApplicationUserclasse que herda da IdentityUserclasse?

Ou há algo que preciso alterar para que essas funções funcionem?

Cybercop
fonte
1
Existe alguma maneira de verificar se um usuário existe com base em outros campos além do endereço de e-mail? Por exemplo, se eu tivesse dois campos chamados CustomerNumber e Postcode para usuários que já existiriam no banco de dados para impedir que qualquer um se registrasse
Jay

Respostas:

127

Você deve especificar um UserTokenProviderpara gerar um 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"));

Você também deve ler este artigo: Adicionando a autenticação de dois fatores a um aplicativo usando a identidade ASP.NET .

Meziantou
fonte
5
o que são "Sample"e "EmailConfirmation"? algum texto que pode ser qualquer coisa?
Cybercop
2
"Sample" = AppName, "EmailConfirmation" = propósito (como os nomes dos parâmetros)
meziantou
5
Sim, mas você terá que usar o mesmo para gerar e validar tokens
meziantou
1
O link está OK. Você coloca este código onde inicializa oUserManager
meziantou
isso faz com que 'Não foi possível carregar o tipo' System.Security.Cryptography.DpapiDataProtector 'do assembly em .netcore
TAHA SULTAN TEMURI
25

No ASP.NET Core hoje em dia é possível configurar um serviço padrão no Startup.cs assim:

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

Não há necessidade de ligar para o DpapiDataProtectionProviderou qualquer coisa parecida. O DefaultTokenProviders () cuidará da chamada para GenerateEmailConfirmationToken do UserManager.

Pisker
fonte
21

Além da resposta aceita, gostaria de acrescentar que essa abordagem não funcionará em sites da Web do Azure, você obteria CryptographicException em vez de um token.

Para consertá-lo para o Azure, implemente seu próprio IDataProtector: veja esta resposta

Um pouco mais detalhes na postagem do blog

trailmax
fonte
13

Minha solução:

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

Meu problema com este código foi resolvido.
Boa sorte, amigos.

Amin Ghaderi
fonte
using Microsoft.Owin.Security.DataProtection;
Amin Ghaderi
Tive que usar DataProtectorTokenProvider <IdentityUser, string> em vez de <User, string> para ambos os genéricos. Além disso, o userId em GeneratePasswordResetToken é o id da string guid e não o userName ou Email.
Dan Randolph
7

Caso mais alguém cometa o mesmo erro que eu. Tentei fazer uma função como a abaixo e com certeza o erro "Nenhum IUserTokenProvider está registrado." foi embora. No entanto, assim que tentei usar o link gerado em "callbackUrl", recebi o erro "Token inválido". Para que funcione, você precisa obter o HttpContext UserManager. Se você estiver usando um aplicativo ASP.NET MVC 5 padrão com contas de usuário individuais, você pode fazer como abaixo.

Código que funciona:

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

Primeiro tente que não funcione, No IUserTokenProvider is registered.se foi, mas a URL criada foi mantida 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("[email protected]");
             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();
     }
Ogglas
fonte
5

De acordo com pisker acima

Em startup.cs você pode usar

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

No .net core 2.0, você pode precisar adicionar ao startup.cs:

using Microsoft.AspNetCore.Identity;

Isso funcionou bem pra mim.

ScottC
fonte
1
Acho que é importante lembrar que esta é uma solução Asp .NET Core, não funcionará com o Asp .NET Framework.
Machado
3

Ao modificar os arquivos de identidade do .NET Core, me deparei com este erro:

NotSupportedException: Nenhum IUserTwoFactorTokenProvider denominado 'Default' está registrado.

o

Microsoft.AspNetCore.Identity.UserManager.GenerateUserTokenAsync

A função não pôde gerar um token porque nenhum provedor estava disponível ao registrar um novo usuário. Este erro pode ser facilmente corrigido!

Se você for como eu, mudou AddDefaultIdentityno Startup.csarquivo para AddIdentity. Eu queria implementar meu próprio usuário herdado do usuário base. Ao fazer isso, perdi os provedores de token padrão. A solução era adicioná-los de volta com AddDefaultTokenProviders().

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

Depois dessa correção, tudo funcionou novamente!

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

Yawar Ali
fonte
1

Recebi o mesmo erro após atualizar o Identity e descobri que era porque eu estava usando o Unity.

Veja este tópico de perguntas sobre a solução: Register IAuthenticationManager with Unity

Também abaixo para referência rápida:

Aqui está o que fiz para que o Unity funcionasse bem com o ASP.NET Identity 2.0:

Eu adicionei o seguinte ao RegisterTypesmétodo na UnityConfigclasse:

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());
Roubar
fonte
1
Eu segui isso, mas não funcionou (para GeneratePasswordResetToken- mas recebi o mesmo erro de "Nenhum IUserTokenProvider está registrado"). Depois de adicionar container.RegisterType<ApplicationUserManager>( new InjectionFactory(c => HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>()));a UnityConfig.cs, funcionou.
0

em IdentityConfig.cs, adicione sua opção de dois fatores:

        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"));
        }
Mohammad Reza Mrg
fonte