8

Hello,

In order to getting password reset work I need to register an IUserTokenProvider instance into DI.

Without it I get exception at following line:

var result = await _userManager.ResetPasswordAsync(user, token, password);
"No IUserTokenProvider named 'PasswordResetTokenProvider' is registered."

That makes sense so I tried to register it in the DI:

services.AddSingleton<IUserTokenProvider<User>, DataProtectorTokenProvider<User>>();

But the interface IUserTokenProvider does not exists. Do you know how to solve this?

Thanks

rudolfdobias
  • 1,778
  • 3
  • 17
  • 40

6 Answers6

26

You can specify one of the built in providers;

services.AddIdentity<User, Role>(options =>{
        options.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider;
    })
    .AddDefaultTokenProviders();

Or create your own IUserTwoFactorTokenProvider and register it like so;

services.AddIdentity<User, Role>(options => {
    options.Tokens.PasswordResetTokenProvider = nameof(MyTokenProvider);
})
.AddTokenProvider<MyTokenProvider>(nameof(MyTokenProvider));
Jeremy Lakeman
  • 9,515
  • 25
  • 29
12

add or correct following lines in startup.cs:

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

you can found more description here

mazhar zarsaw
  • 146
  • 1
  • 3
9

I'm not sure if it's workaround or normal approach, but the IUserTwoFactorTokenProvider interface seems to be a right way. IUserTokenProvider appears to no longer exists.

Figured out that I have to register the provider manually in the identity:

services.AddIdentity<User, Role>(options =>
            {
                ...
                options.Tokens.ProviderMap.Add("Default", new TokenProviderDescriptor(typeof(IUserTwoFactorTokenProvider<User>)));
            })

And the optional configuration in ConfigureServices:

services.Configure<DataProtectionTokenProviderOptions>(o =>
        {
            o.Name = "Default";
            o.TokenLifespan = TimeSpan.FromHours(1);
        });

And the password reset / email validation tokens are working now.

PS: Opened an issue for clarification

rudolfdobias
  • 1,778
  • 3
  • 17
  • 40
6

You have to dig deep into the .NET Core code and find what internals the AddIdentity is doing.

What I found was the following that worked for us as we could not use .AddIdentity() as it overrode the IdentityServer4 middleware.

Instead, we added transients for the all the interfaces needed for UserManager and then used IdentityBuilder class to add the token provider.

NOTE The User class below inherits from IdentityUser as we needed to customize our user table.

// add User Manager related objects into DI configuration
services.AddTransient<IUserStore<User>, UserStore<User, IdentityRole<string>, ApplicationDbContext>>();
services.AddTransient<IRoleStore<IdentityRole<string>>, RoleStore<IdentityRole<string>, ApplicationDbContext>>();
services.AddTransient<IPasswordHasher<User>, PasswordHasher<User>>();
services.AddTransient<ILookupNormalizer, UpperInvariantLookupNormalizer>();
services.AddTransient<IdentityErrorDescriber>();
var identityBuilder = new IdentityBuilder(typeof(User), typeof(IdentityRole<string>), services);
identityBuilder.AddTokenProvider("Default", typeof(DataProtectorTokenProvider<User>));
services.AddTransient<UserManager<User>>();
Stephen Rauch
  • 47,830
  • 31
  • 106
  • 135
Rob
  • 101
  • 1
  • 4
1

Add .AddDefaultTokenProviders(); in ConfigureServices() method in startupclass

 `in public void ConfigureServices(IServiceCollection services)
    {
     services.AddIdentity<RegisterUser, IdentityRole>()
                    .AddEntityFrameworkStores<ContextClass>()
                    .AddDefaultTokenProviders();
    }
    `
mosess
  • 1,043
  • 8
  • 8
0
        services.AddIdentityCore<User>()
        .AddEntityFrameworkStores<ContextClass>()
        .AddDefaultTokenProviders();

It is AddIdentityCore version for only you add User, you might need it .

tiakham
  • 67
  • 1
  • 10