diff --git a/src/Microsoft.AspNetCore.Identity/TokenProviderDescriptor.cs b/src/Microsoft.AspNetCore.Identity/TokenProviderDescriptor.cs
index 993ecfbed..95c2920b3 100644
--- a/src/Microsoft.AspNetCore.Identity/TokenProviderDescriptor.cs
+++ b/src/Microsoft.AspNetCore.Identity/TokenProviderDescriptor.cs
@@ -23,5 +23,10 @@ public TokenProviderDescriptor(Type type)
/// The type that will be used for this token provider.
///
public Type ProviderType { get; }
+
+ ///
+ /// If specified, the instance to be used for the token provider.
+ ///
+ public object ProviderInstance { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Microsoft.AspNetCore.Identity/UserManager.cs b/src/Microsoft.AspNetCore.Identity/UserManager.cs
index 30881435c..d3eff1b91 100644
--- a/src/Microsoft.AspNetCore.Identity/UserManager.cs
+++ b/src/Microsoft.AspNetCore.Identity/UserManager.cs
@@ -98,7 +98,10 @@ public UserManager(IUserStore store,
_context = services.GetService()?.HttpContext;
foreach (var providerName in Options.Tokens.ProviderMap.Keys)
{
- var provider = services.GetRequiredService(Options.Tokens.ProviderMap[providerName].ProviderType) as IUserTwoFactorTokenProvider;
+ var description = Options.Tokens.ProviderMap[providerName];
+
+ var provider = (description.ProviderInstance ?? services.GetRequiredService(description.ProviderType))
+ as IUserTwoFactorTokenProvider;
if (provider != null)
{
RegisterTokenProvider(providerName, provider);
diff --git a/test/Microsoft.AspNetCore.Identity.Test/UserManagerTest.cs b/test/Microsoft.AspNetCore.Identity.Test/UserManagerTest.cs
index 5be34eb51..664bc14f9 100644
--- a/test/Microsoft.AspNetCore.Identity.Test/UserManagerTest.cs
+++ b/test/Microsoft.AspNetCore.Identity.Test/UserManagerTest.cs
@@ -623,6 +623,52 @@ public async Task ClaimMethodsFailWhenStoreNotImplemented()
await Assert.ThrowsAsync(async () => await manager.GetClaimsAsync(null));
}
+ private class ATokenProvider : IUserTwoFactorTokenProvider
+ {
+ public Task CanGenerateTwoFactorTokenAsync(UserManager manager, TestUser user)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task GenerateAsync(string purpose, UserManager manager, TestUser user)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task ValidateAsync(string purpose, string token, UserManager manager, TestUser user)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ [Fact]
+ public void UserManagerWillUseTokenProviderInstance()
+ {
+ var services = new ServiceCollection();
+ var provider = new ATokenProvider();
+ services.AddLogging()
+ .AddIdentity(o => o.Tokens.ProviderMap.Add("A", new TokenProviderDescriptor(typeof(ATokenProvider))
+ {
+ ProviderInstance = provider
+ })).AddUserStore();
+ var manager = services.BuildServiceProvider().GetService>();
+ Assert.ThrowsAsync(() => manager.GenerateUserTokenAsync(new TestUser(), "A", "purpose"));
+ }
+
+ [Fact]
+ public void UserManagerWillUseTokenProviderInstanceOverDefaults()
+ {
+ var services = new ServiceCollection();
+ var provider = new ATokenProvider();
+ services.AddLogging()
+ .AddIdentity(o => o.Tokens.ProviderMap.Add(TokenOptions.DefaultProvider, new TokenProviderDescriptor(typeof(ATokenProvider))
+ {
+ ProviderInstance = provider
+ })).AddUserStore().AddDefaultTokenProviders();
+ var manager = services.BuildServiceProvider().GetService>();
+ Assert.ThrowsAsync(() => manager.GenerateUserTokenAsync(new TestUser(), TokenOptions.DefaultProvider, "purpose"));
+ }
+
[Fact]
public async Task TwoFactorStoreMethodsFailWhenStoreNotImplemented()
{