Żaden IUserTokenProvider nie jest zarejestrowany

102

Niedawno zaktualizowałem Asp.Net Identity Coremój formularz zgłoszeniowy z 1.0 do 2.0.

Są nowe funkcje, które chciałem wypróbować GenerateEmailConfirmationTokenitp.

Używam tego projektu jako odniesienia.

Kiedy użytkownik próbuje się zarejestrować, pojawia się błąd podczas wykonywania metody Register w 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);
}

W linii

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

Pojawia się błąd mówiący:

No IUserTokenProvider is registered.

Na razie chciałem tylko zobaczyć, jaki kod generuje. Czy jest jakaś zmiana, którą muszę wprowadzić w mojej ApplicationUserklasie, która dziedziczy po IdentityUserklasie?

Czy jest coś, co muszę zmienić, aby te funkcje działały?

Cybercop
źródło
1
Czy można w jakiś sposób sprawdzić, czy użytkownik istnieje na podstawie innych pól niż adres e-mail? Na przykład, gdybym miał dwa pola o nazwie CustomerNumber i Postcode dla użytkowników, którzy już wcześniej istnieli w bazie danych, aby uniemożliwić każdemu rejestrację
Jay

Odpowiedzi:

127

Musisz określić, UserTokenProvideraby wygenerować 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"));

Należy również przeczytać ten artykuł: Dodawanie uwierzytelniania dwuskładnikowego do aplikacji przy użyciu tożsamości ASP.NET .

meziantou
źródło
5
jakie są "Sample"i "EmailConfirmation"? jakiś tekst, który może być cokolwiek?
Cybercop,
2
„Sample” = AppName, „EmailConfirmation” = cel (jak nazwy parametrów)
meziantou
5
Tak, ale będziesz musiał użyć tego samego do generowania i sprawdzania poprawności tokenów
meziantou
1
Link jest OK. Ten kod umieszczasz tam, gdzie inicjalizujeszUserManager
meziantou
powoduje to „Nie można załadować typu„ System.Security.Cryptography.DpapiDataProtector ”z zestawu w .netcore
TAHA SULTAN TEMURI
25

W ASP.NET Core można obecnie skonfigurować domyślną usługę w Startup.cs w następujący sposób:

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

Nie ma potrzeby dzwonić do niego DpapiDataProtectionProviderani nic takiego. DefaultTokenProviders () zajmie się wywołaniem GenerateEmailConfirmationToken z UserManager.

pisker
źródło
21

Oprócz zaakceptowanej odpowiedzi chciałbym dodać, że to podejście nie zadziała w Azure Web-Sites, otrzymasz CryptographicException zamiast tokenu.

Aby rozwiązać ten problem na platformie Azure, zaimplementuj własny IDataProtector: zobacz tę odpowiedź

Nieco więcej szczegółów w poście na blogu

trailmax
źródło
13

Moje rozwiązanie:

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

Mój problem z tym kodem rozwiązany.
Powodzenia przyjaciele.

Amin Ghaderi
źródło
przy użyciu Microsoft.Owin.Security.DataProtection;
Amin Ghaderi
Musiałem użyć DataProtectorTokenProvider <IdentityUser, string> zamiast <User, string> dla obu typów generycznych. Również identyfikator użytkownika w GeneratePasswordResetToken jest identyfikatorem ciągu identyfikacyjnego, a nie nazwą użytkownika ani adresem e-mail.
Dan Randolph
7

Na wypadek, gdyby ktoś inny popełnił ten sam błąd co ja. Próbowałem utworzyć funkcję taką jak ta poniżej i na pewno błąd „Nie zarejestrowano IUserTokenProvider”. zniknął. Jednak gdy tylko próbowałem użyć linku wygenerowanego z „callbackUrl”, pojawił się błąd „Nieprawidłowy token”. Aby to działało, musisz pobrać HttpContext UserManager. Jeśli używasz standardowej aplikacji ASP.NET MVC 5 z indywidualnymi kontami użytkowników, możesz to zrobić jak poniżej.

Kod, który działa:

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

Pierwsza próba nie działa, No IUserTokenProvider is registered.zniknęła, ale utworzony adres URL dostaje 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
źródło
5

Jak na piskera powyżej

W startup.cs możesz użyć

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

W .net core 2.0 może być konieczne dodanie do startup.cs:

using Microsoft.AspNetCore.Identity;

To działało dobrze dla mnie.

ScottC
źródło
1
Myślę, że ważne jest, aby pamiętać, że jest to rozwiązanie Asp .NET Core, nie będzie działać z ASP .NET Framework.
Machado,
4

Podczas modyfikowania plików tożsamości .NET Core natknąłem się na ten błąd:

NotSupportedException: Nie zarejestrowano IUserTwoFactorTokenProvider o nazwie „Default”.

Plik

Microsoft.AspNetCore.Identity.UserManager.GenerateUserTokenAsync

funkcja nie mogła wygenerować tokena, ponieważ żaden dostawca nie był dostępny podczas rejestracji nowego użytkownika. Ten błąd można jednak łatwo naprawić!

Jeśli jesteś podobny do mnie, zmieniłeś AddDefaultIdentityw Startup.cspliku na AddIdentity. Chciałem zaimplementować własnego użytkownika, który odziedziczył po użytkowniku podstawowym. W ten sposób straciłem domyślnych dostawców tokenów. Rozwiązaniem było dodanie ich z powrotem za pomocą AddDefaultTokenProviders().

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

Po tej poprawce wszystko znów działało!

źródło: https://mattferderer.com/NotSupportedException-No-IUserTwoFactorTokenProvider-tuser-named-default-registered

Yawar Ali
źródło
1

Po zaktualizowaniu tożsamości wystąpił ten sam błąd i stwierdziłem, że jest to spowodowane korzystaniem z aparatu Unity.

Zobacz ten wątek pytania na temat rozwiązania: Zarejestruj IAuthenticationManager w Unity

Również poniżej dla szybkiego odniesienia:

Oto, co zrobiłem, aby Unity działało dobrze z ASP.NET Identity 2.0:

Dodałem do RegisterTypesmetody w UnityConfigklasie:

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());
Obrabować
źródło
1
Postępowałem zgodnie z tym, ale nie zadziałało (dla GeneratePasswordResetToken- ale otrzymałem ten sam błąd „Nie zarejestrowano IUserTokenProvider”). Po dodaniu container.RegisterType<ApplicationUserManager>( new InjectionFactory(c => HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>()));do UnityConfig.cs, to działało.
0

w IdentityConfig.cs, dodaj opcję dwuskładnikową:

        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
źródło