Make roles optional in Extensions.Identity

This commit is contained in:
Hao Kung 2017-06-20 13:32:42 -07:00
parent f91e3ff342
commit f555a26b4a
50 changed files with 4456 additions and 3298 deletions

224
IdentityCore.sln Normal file
View File

@ -0,0 +1,224 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26507.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0F647068-6602-4E24-B1DC-8ED91481A50A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{52D59F18-62D2-4D17-8CF2-BE192445AF8E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity", "src\Microsoft.AspNetCore.Identity\Microsoft.AspNetCore.Identity.csproj", "{1729302E-A58E-4652-B639-5B6B68DA2748}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.Test", "test\Microsoft.AspNetCore.Identity.Test\Microsoft.AspNetCore.Identity.Test.csproj", "{2CF3927B-19E4-4866-9BAA-2C131580E7C3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.InMemory.Test", "test\Microsoft.AspNetCore.Identity.InMemory.Test\Microsoft.AspNetCore.Identity.InMemory.Test.csproj", "{65161409-C4C4-4D63-A73B-231FCFF4D503}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{58D94A0E-C2B7-43A7-8826-99ECBB1E0A50}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IdentitySample.Mvc", "samples\IdentitySample.Mvc\IdentitySample.Mvc.csproj", "{E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test", "test\Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test\Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test.csproj", "{37236EA3-915D-46D5-997C-DF513C500E4B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test", "test\Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test\Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test.csproj", "{EA7EB28F-53B8-4009-9C6B-74DB090CA8DD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.EntityFrameworkCore", "src\Microsoft.AspNetCore.Identity.EntityFrameworkCore\Microsoft.AspNetCore.Identity.EntityFrameworkCore.csproj", "{4490894C-3572-4E63-86F1-EE5105CE8A06}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNet.Identity.AspNetCoreCompat", "src\Microsoft.AspNet.Identity.AspNetCoreCompat\Microsoft.AspNet.Identity.AspNetCoreCompat.csproj", "{6A74C6EA-B241-4D6B-BCE4-BF89EC1D2475}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.Specification.Tests", "src\Microsoft.AspNetCore.Identity.Specification.Tests\Microsoft.AspNetCore.Identity.Specification.Tests.csproj", "{5608E828-DD54-4E2A-B73C-FC22268BE797}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Identity.Core", "src\Microsoft.Extensions.Identity.Core\Microsoft.Extensions.Identity.Core.csproj", "{D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Identity.Stores", "src\Microsoft.Extensions.Identity.Stores\Microsoft.Extensions.Identity.Stores.csproj", "{FADA11FC-DC06-4832-A569-7B2374A6CD42}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|Mixed Platforms = Debug|Mixed Platforms
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|Mixed Platforms = Release|Mixed Platforms
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1729302E-A58E-4652-B639-5B6B68DA2748}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1729302E-A58E-4652-B639-5B6B68DA2748}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1729302E-A58E-4652-B639-5B6B68DA2748}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{1729302E-A58E-4652-B639-5B6B68DA2748}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{1729302E-A58E-4652-B639-5B6B68DA2748}.Debug|x64.ActiveCfg = Debug|Any CPU
{1729302E-A58E-4652-B639-5B6B68DA2748}.Debug|x64.Build.0 = Debug|Any CPU
{1729302E-A58E-4652-B639-5B6B68DA2748}.Debug|x86.ActiveCfg = Debug|Any CPU
{1729302E-A58E-4652-B639-5B6B68DA2748}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1729302E-A58E-4652-B639-5B6B68DA2748}.Release|Any CPU.Build.0 = Release|Any CPU
{1729302E-A58E-4652-B639-5B6B68DA2748}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{1729302E-A58E-4652-B639-5B6B68DA2748}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{1729302E-A58E-4652-B639-5B6B68DA2748}.Release|x64.ActiveCfg = Release|Any CPU
{1729302E-A58E-4652-B639-5B6B68DA2748}.Release|x64.Build.0 = Release|Any CPU
{1729302E-A58E-4652-B639-5B6B68DA2748}.Release|x86.ActiveCfg = Release|Any CPU
{2CF3927B-19E4-4866-9BAA-2C131580E7C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2CF3927B-19E4-4866-9BAA-2C131580E7C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2CF3927B-19E4-4866-9BAA-2C131580E7C3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{2CF3927B-19E4-4866-9BAA-2C131580E7C3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{2CF3927B-19E4-4866-9BAA-2C131580E7C3}.Debug|x64.ActiveCfg = Debug|Any CPU
{2CF3927B-19E4-4866-9BAA-2C131580E7C3}.Debug|x64.Build.0 = Debug|Any CPU
{2CF3927B-19E4-4866-9BAA-2C131580E7C3}.Debug|x86.ActiveCfg = Debug|Any CPU
{2CF3927B-19E4-4866-9BAA-2C131580E7C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2CF3927B-19E4-4866-9BAA-2C131580E7C3}.Release|Any CPU.Build.0 = Release|Any CPU
{2CF3927B-19E4-4866-9BAA-2C131580E7C3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{2CF3927B-19E4-4866-9BAA-2C131580E7C3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{2CF3927B-19E4-4866-9BAA-2C131580E7C3}.Release|x64.ActiveCfg = Release|Any CPU
{2CF3927B-19E4-4866-9BAA-2C131580E7C3}.Release|x64.Build.0 = Release|Any CPU
{2CF3927B-19E4-4866-9BAA-2C131580E7C3}.Release|x86.ActiveCfg = Release|Any CPU
{65161409-C4C4-4D63-A73B-231FCFF4D503}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{65161409-C4C4-4D63-A73B-231FCFF4D503}.Debug|Any CPU.Build.0 = Debug|Any CPU
{65161409-C4C4-4D63-A73B-231FCFF4D503}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{65161409-C4C4-4D63-A73B-231FCFF4D503}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{65161409-C4C4-4D63-A73B-231FCFF4D503}.Debug|x64.ActiveCfg = Debug|Any CPU
{65161409-C4C4-4D63-A73B-231FCFF4D503}.Debug|x64.Build.0 = Debug|Any CPU
{65161409-C4C4-4D63-A73B-231FCFF4D503}.Debug|x86.ActiveCfg = Debug|Any CPU
{65161409-C4C4-4D63-A73B-231FCFF4D503}.Release|Any CPU.ActiveCfg = Release|Any CPU
{65161409-C4C4-4D63-A73B-231FCFF4D503}.Release|Any CPU.Build.0 = Release|Any CPU
{65161409-C4C4-4D63-A73B-231FCFF4D503}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{65161409-C4C4-4D63-A73B-231FCFF4D503}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{65161409-C4C4-4D63-A73B-231FCFF4D503}.Release|x64.ActiveCfg = Release|Any CPU
{65161409-C4C4-4D63-A73B-231FCFF4D503}.Release|x64.Build.0 = Release|Any CPU
{65161409-C4C4-4D63-A73B-231FCFF4D503}.Release|x86.ActiveCfg = Release|Any CPU
{E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6}.Debug|x64.ActiveCfg = Debug|Any CPU
{E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6}.Debug|x64.Build.0 = Debug|Any CPU
{E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6}.Debug|x86.ActiveCfg = Debug|Any CPU
{E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6}.Release|Any CPU.Build.0 = Release|Any CPU
{E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6}.Release|x64.ActiveCfg = Release|Any CPU
{E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6}.Release|x64.Build.0 = Release|Any CPU
{E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6}.Release|x86.ActiveCfg = Release|Any CPU
{37236EA3-915D-46D5-997C-DF513C500E4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{37236EA3-915D-46D5-997C-DF513C500E4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{37236EA3-915D-46D5-997C-DF513C500E4B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{37236EA3-915D-46D5-997C-DF513C500E4B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{37236EA3-915D-46D5-997C-DF513C500E4B}.Debug|x64.ActiveCfg = Debug|Any CPU
{37236EA3-915D-46D5-997C-DF513C500E4B}.Debug|x64.Build.0 = Debug|Any CPU
{37236EA3-915D-46D5-997C-DF513C500E4B}.Debug|x86.ActiveCfg = Debug|Any CPU
{37236EA3-915D-46D5-997C-DF513C500E4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{37236EA3-915D-46D5-997C-DF513C500E4B}.Release|Any CPU.Build.0 = Release|Any CPU
{37236EA3-915D-46D5-997C-DF513C500E4B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{37236EA3-915D-46D5-997C-DF513C500E4B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{37236EA3-915D-46D5-997C-DF513C500E4B}.Release|x64.ActiveCfg = Release|Any CPU
{37236EA3-915D-46D5-997C-DF513C500E4B}.Release|x64.Build.0 = Release|Any CPU
{37236EA3-915D-46D5-997C-DF513C500E4B}.Release|x86.ActiveCfg = Release|Any CPU
{EA7EB28F-53B8-4009-9C6B-74DB090CA8DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EA7EB28F-53B8-4009-9C6B-74DB090CA8DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EA7EB28F-53B8-4009-9C6B-74DB090CA8DD}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{EA7EB28F-53B8-4009-9C6B-74DB090CA8DD}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{EA7EB28F-53B8-4009-9C6B-74DB090CA8DD}.Debug|x64.ActiveCfg = Debug|Any CPU
{EA7EB28F-53B8-4009-9C6B-74DB090CA8DD}.Debug|x64.Build.0 = Debug|Any CPU
{EA7EB28F-53B8-4009-9C6B-74DB090CA8DD}.Debug|x86.ActiveCfg = Debug|Any CPU
{EA7EB28F-53B8-4009-9C6B-74DB090CA8DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EA7EB28F-53B8-4009-9C6B-74DB090CA8DD}.Release|Any CPU.Build.0 = Release|Any CPU
{EA7EB28F-53B8-4009-9C6B-74DB090CA8DD}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{EA7EB28F-53B8-4009-9C6B-74DB090CA8DD}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{EA7EB28F-53B8-4009-9C6B-74DB090CA8DD}.Release|x64.ActiveCfg = Release|Any CPU
{EA7EB28F-53B8-4009-9C6B-74DB090CA8DD}.Release|x64.Build.0 = Release|Any CPU
{EA7EB28F-53B8-4009-9C6B-74DB090CA8DD}.Release|x86.ActiveCfg = Release|Any CPU
{4490894C-3572-4E63-86F1-EE5105CE8A06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4490894C-3572-4E63-86F1-EE5105CE8A06}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4490894C-3572-4E63-86F1-EE5105CE8A06}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{4490894C-3572-4E63-86F1-EE5105CE8A06}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{4490894C-3572-4E63-86F1-EE5105CE8A06}.Debug|x64.ActiveCfg = Debug|Any CPU
{4490894C-3572-4E63-86F1-EE5105CE8A06}.Debug|x64.Build.0 = Debug|Any CPU
{4490894C-3572-4E63-86F1-EE5105CE8A06}.Debug|x86.ActiveCfg = Debug|Any CPU
{4490894C-3572-4E63-86F1-EE5105CE8A06}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4490894C-3572-4E63-86F1-EE5105CE8A06}.Release|Any CPU.Build.0 = Release|Any CPU
{4490894C-3572-4E63-86F1-EE5105CE8A06}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{4490894C-3572-4E63-86F1-EE5105CE8A06}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{4490894C-3572-4E63-86F1-EE5105CE8A06}.Release|x64.ActiveCfg = Release|Any CPU
{4490894C-3572-4E63-86F1-EE5105CE8A06}.Release|x64.Build.0 = Release|Any CPU
{4490894C-3572-4E63-86F1-EE5105CE8A06}.Release|x86.ActiveCfg = Release|Any CPU
{6A74C6EA-B241-4D6B-BCE4-BF89EC1D2475}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6A74C6EA-B241-4D6B-BCE4-BF89EC1D2475}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6A74C6EA-B241-4D6B-BCE4-BF89EC1D2475}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{6A74C6EA-B241-4D6B-BCE4-BF89EC1D2475}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{6A74C6EA-B241-4D6B-BCE4-BF89EC1D2475}.Debug|x64.ActiveCfg = Debug|Any CPU
{6A74C6EA-B241-4D6B-BCE4-BF89EC1D2475}.Debug|x64.Build.0 = Debug|Any CPU
{6A74C6EA-B241-4D6B-BCE4-BF89EC1D2475}.Debug|x86.ActiveCfg = Debug|Any CPU
{6A74C6EA-B241-4D6B-BCE4-BF89EC1D2475}.Debug|x86.Build.0 = Debug|Any CPU
{6A74C6EA-B241-4D6B-BCE4-BF89EC1D2475}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6A74C6EA-B241-4D6B-BCE4-BF89EC1D2475}.Release|Any CPU.Build.0 = Release|Any CPU
{6A74C6EA-B241-4D6B-BCE4-BF89EC1D2475}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{6A74C6EA-B241-4D6B-BCE4-BF89EC1D2475}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{6A74C6EA-B241-4D6B-BCE4-BF89EC1D2475}.Release|x64.ActiveCfg = Release|Any CPU
{6A74C6EA-B241-4D6B-BCE4-BF89EC1D2475}.Release|x64.Build.0 = Release|Any CPU
{6A74C6EA-B241-4D6B-BCE4-BF89EC1D2475}.Release|x86.ActiveCfg = Release|Any CPU
{6A74C6EA-B241-4D6B-BCE4-BF89EC1D2475}.Release|x86.Build.0 = Release|Any CPU
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Debug|x64.ActiveCfg = Debug|Any CPU
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Debug|x64.Build.0 = Debug|Any CPU
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Debug|x86.ActiveCfg = Debug|Any CPU
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Debug|x86.Build.0 = Debug|Any CPU
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Release|Any CPU.Build.0 = Release|Any CPU
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Release|x64.ActiveCfg = Release|Any CPU
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Release|x64.Build.0 = Release|Any CPU
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Release|x86.ActiveCfg = Release|Any CPU
{5608E828-DD54-4E2A-B73C-FC22268BE797}.Release|x86.Build.0 = Release|Any CPU
{D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Debug|x64.ActiveCfg = Debug|Any CPU
{D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Debug|x64.Build.0 = Debug|Any CPU
{D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Debug|x86.ActiveCfg = Debug|Any CPU
{D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Debug|x86.Build.0 = Debug|Any CPU
{D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Release|Any CPU.Build.0 = Release|Any CPU
{D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Release|x64.ActiveCfg = Release|Any CPU
{D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Release|x64.Build.0 = Release|Any CPU
{D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Release|x86.ActiveCfg = Release|Any CPU
{D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Release|x86.Build.0 = Release|Any CPU
{FADA11FC-DC06-4832-A569-7B2374A6CD42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FADA11FC-DC06-4832-A569-7B2374A6CD42}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FADA11FC-DC06-4832-A569-7B2374A6CD42}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{FADA11FC-DC06-4832-A569-7B2374A6CD42}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{FADA11FC-DC06-4832-A569-7B2374A6CD42}.Debug|x64.ActiveCfg = Debug|Any CPU
{FADA11FC-DC06-4832-A569-7B2374A6CD42}.Debug|x64.Build.0 = Debug|Any CPU
{FADA11FC-DC06-4832-A569-7B2374A6CD42}.Debug|x86.ActiveCfg = Debug|Any CPU
{FADA11FC-DC06-4832-A569-7B2374A6CD42}.Debug|x86.Build.0 = Debug|Any CPU
{FADA11FC-DC06-4832-A569-7B2374A6CD42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FADA11FC-DC06-4832-A569-7B2374A6CD42}.Release|Any CPU.Build.0 = Release|Any CPU
{FADA11FC-DC06-4832-A569-7B2374A6CD42}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{FADA11FC-DC06-4832-A569-7B2374A6CD42}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{FADA11FC-DC06-4832-A569-7B2374A6CD42}.Release|x64.ActiveCfg = Release|Any CPU
{FADA11FC-DC06-4832-A569-7B2374A6CD42}.Release|x64.Build.0 = Release|Any CPU
{FADA11FC-DC06-4832-A569-7B2374A6CD42}.Release|x86.ActiveCfg = Release|Any CPU
{FADA11FC-DC06-4832-A569-7B2374A6CD42}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{1729302E-A58E-4652-B639-5B6B68DA2748} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
{2CF3927B-19E4-4866-9BAA-2C131580E7C3} = {52D59F18-62D2-4D17-8CF2-BE192445AF8E}
{65161409-C4C4-4D63-A73B-231FCFF4D503} = {52D59F18-62D2-4D17-8CF2-BE192445AF8E}
{E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6} = {58D94A0E-C2B7-43A7-8826-99ECBB1E0A50}
{37236EA3-915D-46D5-997C-DF513C500E4B} = {52D59F18-62D2-4D17-8CF2-BE192445AF8E}
{EA7EB28F-53B8-4009-9C6B-74DB090CA8DD} = {52D59F18-62D2-4D17-8CF2-BE192445AF8E}
{4490894C-3572-4E63-86F1-EE5105CE8A06} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
{6A74C6EA-B241-4D6B-BCE4-BF89EC1D2475} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
{5608E828-DD54-4E2A-B73C-FC22268BE797} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
{D5905D78-A32E-44B8-8F21-EDAEDC95D9B8} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
{FADA11FC-DC06-4832-A569-7B2374A6CD42} = {0F647068-6602-4E24-B1DC-8ED91481A50A}
EndGlobalSection
EndGlobal

5
build/repo.props Normal file
View File

@ -0,0 +1,5 @@
<Project>
<ItemGroup>
<ExcludeSolutions Include="$(RepositoryRoot)IdentityCore.sln" />
</ItemGroup>
</Project>

View File

@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// Base class for the Entity Framework database context used for identity.
/// </summary>
/// <typeparam name="TUser">The type of the user objects.</typeparam>
public class IdentityDbContext<TUser> : IdentityDbContext<TUser, IdentityRole, string> where TUser : IdentityUser
public class IdentityDbContext<TUser> : IdentityDbContext<TUser, string> where TUser : IdentityUser
{
/// <summary>
/// Initializes a new instance of <see cref="IdentityDbContext"/>.
@ -41,6 +41,27 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
protected IdentityDbContext() { }
}
/// <summary>
/// Base class for the Entity Framework database context used for identity.
/// </summary>
/// <typeparam name="TUser">The type of user objects.</typeparam>
/// <typeparam name="TKey">The type of the primary key for users and roles.</typeparam>
public class IdentityDbContext<TUser, TKey> : IdentityDbContext<TUser, TKey, IdentityUserClaim<TKey>, IdentityUserLogin<TKey>, IdentityUserToken<TKey>>
where TUser : IdentityUser<TKey>
where TKey : IEquatable<TKey>
{
/// <summary>
/// Initializes a new instance of the db context.
/// </summary>
/// <param name="options">The options to be used by a <see cref="DbContext"/>.</param>
public IdentityDbContext(DbContextOptions options) : base(options) { }
/// <summary>
/// Initializes a new instance of the class.
/// </summary>
protected IdentityDbContext() { }
}
/// <summary>
/// Base class for the Entity Framework database context used for identity.
/// </summary>
@ -68,21 +89,15 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// Base class for the Entity Framework database context used for identity.
/// </summary>
/// <typeparam name="TUser">The type of user objects.</typeparam>
/// <typeparam name="TRole">The type of role objects.</typeparam>
/// <typeparam name="TKey">The type of the primary key for users and roles.</typeparam>
/// <typeparam name="TUserClaim">The type of the user claim object.</typeparam>
/// <typeparam name="TUserRole">The type of the user role object.</typeparam>
/// <typeparam name="TUserLogin">The type of the user login object.</typeparam>
/// <typeparam name="TRoleClaim">The type of the role claim object.</typeparam>
/// <typeparam name="TUserToken">The type of the user token object.</typeparam>
public abstract class IdentityDbContext<TUser, TRole, TKey, TUserClaim, TUserRole, TUserLogin, TRoleClaim, TUserToken> : DbContext
where TUser : IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin, TUserToken>
where TRole : IdentityRole<TKey, TUserRole, TRoleClaim>
public abstract class IdentityDbContext<TUser, TKey, TUserClaim, TUserLogin, TUserToken> : DbContext
where TUser : IdentityUser<TKey>
where TKey : IEquatable<TKey>
where TUserClaim : IdentityUserClaim<TKey>
where TUserRole : IdentityUserRole<TKey>
where TUserLogin : IdentityUserLogin<TKey>
where TRoleClaim : IdentityRoleClaim<TKey>
where TUserToken : IdentityUserToken<TKey>
{
/// <summary>
@ -111,26 +126,11 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// </summary>
public DbSet<TUserLogin> UserLogins { get; set; }
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of User roles.
/// </summary>
public DbSet<TUserRole> UserRoles { get; set; }
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of User tokens.
/// </summary>
public DbSet<TUserToken> UserTokens { get; set; }
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of roles.
/// </summary>
public DbSet<TRole> Roles { get; set; }
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of role claims.
/// </summary>
public DbSet<TRoleClaim> RoleClaims { get; set; }
/// <summary>
/// Configures the schema needed for the identity framework.
/// </summary>
@ -155,10 +155,90 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
// Replace with b.HasMany<IdentityUserClaim>().
b.HasMany<TUserClaim>().WithOne().HasForeignKey(uc => uc.UserId).IsRequired();
b.HasMany<TUserLogin>().WithOne().HasForeignKey(ul => ul.UserId).IsRequired();
b.HasMany<TUserRole>().WithOne().HasForeignKey(ur => ur.UserId).IsRequired();
b.HasMany<TUserToken>().WithOne().HasForeignKey(ut => ut.UserId).IsRequired();
});
builder.Entity<TUserClaim>(b =>
{
b.HasKey(uc => uc.Id);
b.ToTable("AspNetUserClaims");
});
builder.Entity<TUserLogin>(b =>
{
b.HasKey(l => new { l.LoginProvider, l.ProviderKey });
b.ToTable("AspNetUserLogins");
});
builder.Entity<TUserToken>(b =>
{
b.HasKey(l => new { l.UserId, l.LoginProvider, l.Name });
b.ToTable("AspNetUserTokens");
});
}
}
/// <summary>
/// Base class for the Entity Framework database context used for identity.
/// </summary>
/// <typeparam name="TUser">The type of user objects.</typeparam>
/// <typeparam name="TRole">The type of role objects.</typeparam>
/// <typeparam name="TKey">The type of the primary key for users and roles.</typeparam>
/// <typeparam name="TUserClaim">The type of the user claim object.</typeparam>
/// <typeparam name="TUserRole">The type of the user role object.</typeparam>
/// <typeparam name="TUserLogin">The type of the user login object.</typeparam>
/// <typeparam name="TRoleClaim">The type of the role claim object.</typeparam>
/// <typeparam name="TUserToken">The type of the user token object.</typeparam>
public abstract class IdentityDbContext<TUser, TRole, TKey, TUserClaim, TUserRole, TUserLogin, TRoleClaim, TUserToken> : IdentityDbContext<TUser, TKey, TUserClaim, TUserLogin, TUserToken>
where TUser : IdentityUser<TKey>
where TRole : IdentityRole<TKey>
where TKey : IEquatable<TKey>
where TUserClaim : IdentityUserClaim<TKey>
where TUserRole : IdentityUserRole<TKey>
where TUserLogin : IdentityUserLogin<TKey>
where TRoleClaim : IdentityRoleClaim<TKey>
where TUserToken : IdentityUserToken<TKey>
{
/// <summary>
/// Initializes a new instance of the class.
/// </summary>
/// <param name="options">The options to be used by a <see cref="DbContext"/>.</param>
public IdentityDbContext(DbContextOptions options) : base(options) { }
/// <summary>
/// Initializes a new instance of the class.
/// </summary>
protected IdentityDbContext() { }
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of User roles.
/// </summary>
public DbSet<TUserRole> UserRoles { get; set; }
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of roles.
/// </summary>
public DbSet<TRole> Roles { get; set; }
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of role claims.
/// </summary>
public DbSet<TRoleClaim> RoleClaims { get; set; }
/// <summary>
/// Configures the schema needed for the identity framework.
/// </summary>
/// <param name="builder">
/// The builder being used to construct the model for this context.
/// </param>
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<TUser>(b =>
{
b.HasMany<TUserRole>().WithOne().HasForeignKey(ur => ur.UserId).IsRequired();
});
builder.Entity<TRole>(b =>
{
b.HasKey(r => r.Id);
@ -173,35 +253,17 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
b.HasMany<TRoleClaim>().WithOne().HasForeignKey(rc => rc.RoleId).IsRequired();
});
builder.Entity<TUserClaim>(b =>
{
b.HasKey(uc => uc.Id);
b.ToTable("AspNetUserClaims");
});
builder.Entity<TRoleClaim>(b =>
builder.Entity<TRoleClaim>(b =>
{
b.HasKey(rc => rc.Id);
b.ToTable("AspNetRoleClaims");
});
builder.Entity<TUserRole>(b =>
builder.Entity<TUserRole>(b =>
{
b.HasKey(r => new { r.UserId, r.RoleId });
b.ToTable("AspNetUserRoles");
});
builder.Entity<TUserLogin>(b =>
{
b.HasKey(l => new { l.LoginProvider, l.ProviderKey });
b.ToTable("AspNetUserLogins");
});
builder.Entity<TUserToken>(b =>
{
b.HasKey(l => new { l.UserId, l.LoginProvider, l.Name });
b.ToTable("AspNetUserTokens");
});
}
}
}

View File

@ -30,32 +30,68 @@ namespace Microsoft.Extensions.DependencyInjection
private static void AddStores(IServiceCollection services, Type userType, Type roleType, Type contextType)
{
var identityUserType = FindGenericBaseType(userType, typeof(IdentityUser<,,,,>));
var identityUserType = FindGenericBaseType(userType, typeof(IdentityUser<>));
if (identityUserType == null)
{
throw new InvalidOperationException(Resources.NotIdentityUser);
}
var identityRoleType = FindGenericBaseType(roleType, typeof(IdentityRole<,,>));
if (identityRoleType == null)
var keyType = identityUserType.GenericTypeArguments[0];
if (roleType != null)
{
throw new InvalidOperationException(Resources.NotIdentityRole);
var identityRoleType = FindGenericBaseType(roleType, typeof(IdentityRole<>));
if (identityRoleType == null)
{
throw new InvalidOperationException(Resources.NotIdentityRole);
}
Type userStoreType = null;
Type roleStoreType = null;
var identityContext = FindGenericBaseType(contextType, typeof(IdentityDbContext<,,,,,,,>));
if (identityContext == null)
{
// If its a custom DbContext, we can only add the default POCOs
userStoreType = typeof(UserStore<,,,>).MakeGenericType(userType, roleType, contextType, keyType);
roleStoreType = typeof(RoleStore<,,>).MakeGenericType(roleType, contextType, keyType);
}
else
{
userStoreType = typeof(UserStore<,,,,,,,,>).MakeGenericType(userType, roleType, contextType,
identityContext.GenericTypeArguments[2],
identityContext.GenericTypeArguments[3],
identityContext.GenericTypeArguments[4],
identityContext.GenericTypeArguments[5],
identityContext.GenericTypeArguments[7],
identityContext.GenericTypeArguments[6]);
roleStoreType = typeof(RoleStore<,,,,>).MakeGenericType(roleType, contextType,
identityContext.GenericTypeArguments[2],
identityContext.GenericTypeArguments[4],
identityContext.GenericTypeArguments[6]);
}
services.TryAddScoped(typeof(IUserStore<>).MakeGenericType(userType), userStoreType);
services.TryAddScoped(typeof(IRoleStore<>).MakeGenericType(roleType), roleStoreType);
}
else
{ // No Roles
Type userStoreType = null;
var identityContext = FindGenericBaseType(contextType, typeof(IdentityDbContext<,,,,>));
if (identityContext == null)
{
// If its a custom DbContext, we can only add the default POCOs
userStoreType = typeof(UserStore<,,,>).MakeGenericType(userType, roleType, contextType, keyType);
}
else
{
userStoreType = typeof(UserOnlyStore<,,,,,>).MakeGenericType(userType, roleType, contextType,
identityContext.GenericTypeArguments[1],
identityContext.GenericTypeArguments[2],
identityContext.GenericTypeArguments[3],
identityContext.GenericTypeArguments[4]);
}
services.TryAddScoped(typeof(IUserStore<>).MakeGenericType(userType), userStoreType);
}
services.TryAddScoped(
typeof(IUserStore<>).MakeGenericType(userType),
typeof(UserStore<,,,,,,,,>).MakeGenericType(userType, roleType, contextType,
identityUserType.GenericTypeArguments[0],
identityUserType.GenericTypeArguments[1],
identityUserType.GenericTypeArguments[2],
identityUserType.GenericTypeArguments[3],
identityUserType.GenericTypeArguments[4],
identityRoleType.GenericTypeArguments[2]));
services.TryAddScoped(
typeof(IRoleStore<>).MakeGenericType(roleType),
typeof(RoleStore<,,,,>).MakeGenericType(roleType, contextType,
identityRoleType.GenericTypeArguments[0],
identityRoleType.GenericTypeArguments[1],
identityRoleType.GenericTypeArguments[2]));
}
private static TypeInfo FindGenericBaseType(Type currentType, Type genericBaseType)

View File

@ -15,64 +15,56 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// </summary>
internal static string NotIdentityRole
{
get { return GetString("NotIdentityRole"); }
get => GetString("NotIdentityRole");
}
/// <summary>
/// AddEntityFrameworkStores can only be called with a role that derives from IdentityRole&lt;TKey, TUserRole, TRoleClaim&gt;.
/// </summary>
internal static string FormatNotIdentityRole()
{
return GetString("NotIdentityRole");
}
=> GetString("NotIdentityRole");
/// <summary>
/// AddEntityFrameworkStores can only be called with a user that derives from IdentityUser&lt;TKey, TUserClaim, TUserRole, TUserLogin, TUserToken&gt;.
/// </summary>
internal static string NotIdentityUser
{
get { return GetString("NotIdentityUser"); }
get => GetString("NotIdentityUser");
}
/// <summary>
/// AddEntityFrameworkStores can only be called with a user that derives from IdentityUser&lt;TKey, TUserClaim, TUserRole, TUserLogin, TUserToken&gt;.
/// </summary>
internal static string FormatNotIdentityUser()
{
return GetString("NotIdentityUser");
}
=> GetString("NotIdentityUser");
/// <summary>
/// Role {0} does not exist.
/// </summary>
internal static string RoleNotFound
{
get { return GetString("RoleNotFound"); }
get => GetString("RoleNotFound");
}
/// <summary>
/// Role {0} does not exist.
/// </summary>
internal static string FormatRoleNotFound(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("RoleNotFound"), p0);
}
=> string.Format(CultureInfo.CurrentCulture, GetString("RoleNotFound"), p0);
/// <summary>
/// Value cannot be null or empty.
/// </summary>
internal static string ValueCannotBeNullOrEmpty
{
get { return GetString("ValueCannotBeNullOrEmpty"); }
get => GetString("ValueCannotBeNullOrEmpty");
}
/// <summary>
/// Value cannot be null or empty.
/// </summary>
internal static string FormatValueCannotBeNullOrEmpty()
{
return GetString("ValueCannotBeNullOrEmpty");
}
=> GetString("ValueCannotBeNullOrEmpty");
private static string GetString(string name, params string[] formatterNames)
{

View File

@ -9,7 +9,6 @@ using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
{
@ -77,7 +76,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
public class RoleStore<TRole, TContext, TKey, TUserRole, TRoleClaim> :
IQueryableRoleStore<TRole>,
IRoleClaimStore<TRole>
where TRole : IdentityRole<TKey, TUserRole, TRoleClaim>
where TRole : IdentityRole<TKey>
where TKey : IEquatable<TKey>
where TContext : DbContext
where TUserRole : IdentityUserRole<TKey>, new()
@ -361,10 +360,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// <summary>
/// Dispose the stores
/// </summary>
public void Dispose()
{
_disposed = true;
}
public void Dispose() => _disposed = true;
/// <summary>
/// Get the claims associated with the specified <paramref name="role"/> as an asynchronous operation.
@ -434,10 +430,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// <summary>
/// A navigation property for the roles the store contains.
/// </summary>
public virtual IQueryable<TRole> Roles
{
get { return Context.Set<TRole>(); }
}
public virtual IQueryable<TRole> Roles => Context.Set<TRole>();
private DbSet<TRoleClaim> RoleClaims { get { return Context.Set<TRoleClaim>(); } }
@ -448,8 +441,6 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// <param name="claim">The associated claim.</param>
/// <returns>The role claim entity.</returns>
protected virtual TRoleClaim CreateRoleClaim(TRole role, Claim claim)
{
return new TRoleClaim { RoleId = role.Id, ClaimType = claim.Type, ClaimValue = claim.Value };
}
=> new TRoleClaim { RoleId = role.Id, ClaimType = claim.Type, ClaimValue = claim.Value };
}
}

View File

@ -0,0 +1,567 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
{
/// <summary>
/// Creates a new instance of a persistence store for the specified user type.
/// </summary>
/// <typeparam name="TUser">The type representing a user.</typeparam>
public class UserOnlyStore<TUser> : UserOnlyStore<TUser, DbContext, string> where TUser : IdentityUser<string>, new()
{
/// <summary>
/// Constructs a new instance of <see cref="UserOnlyStore{TUser}"/>.
/// </summary>
/// <param name="context">The <see cref="DbContext"/>.</param>
/// <param name="describer">The <see cref="IdentityErrorDescriber"/>.</param>
public UserOnlyStore(DbContext context, IdentityErrorDescriber describer = null) : base(context, describer) { }
}
/// <summary>
/// Represents a new instance of a persistence store for the specified user and role types.
/// </summary>
/// <typeparam name="TUser">The type representing a user.</typeparam>
/// <typeparam name="TContext">The type of the data context class used to access the store.</typeparam>
public class UserOnlyStore<TUser, TContext> : UserOnlyStore<TUser, TContext, string>
where TUser : IdentityUser<string>
where TContext : DbContext
{
/// <summary>
/// Constructs a new instance of <see cref="UserStore{TUser, TRole, TContext}"/>.
/// </summary>
/// <param name="context">The <see cref="DbContext"/>.</param>
/// <param name="describer">The <see cref="IdentityErrorDescriber"/>.</param>
public UserOnlyStore(TContext context, IdentityErrorDescriber describer = null) : base(context, describer) { }
}
/// <summary>
/// Represents a new instance of a persistence store for the specified user and role types.
/// </summary>
/// <typeparam name="TUser">The type representing a user.</typeparam>
/// <typeparam name="TContext">The type of the data context class used to access the store.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a role.</typeparam>
public class UserOnlyStore<TUser, TContext, TKey> : UserOnlyStore<TUser, TContext, TKey, IdentityUserClaim<TKey>, IdentityUserLogin<TKey>, IdentityUserToken<TKey>>
where TUser : IdentityUser<TKey>
where TContext : DbContext
where TKey : IEquatable<TKey>
{
/// <summary>
/// Constructs a new instance of <see cref="UserStore{TUser, TRole, TContext, TKey}"/>.
/// </summary>
/// <param name="context">The <see cref="DbContext"/>.</param>
/// <param name="describer">The <see cref="IdentityErrorDescriber"/>.</param>
public UserOnlyStore(TContext context, IdentityErrorDescriber describer = null) : base(context, describer) { }
}
/// <summary>
/// Represents a new instance of a persistence store for the specified user and role types.
/// </summary>
/// <typeparam name="TUser">The type representing a user.</typeparam>
/// <typeparam name="TContext">The type of the data context class used to access the store.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a role.</typeparam>
/// <typeparam name="TUserClaim">The type representing a claim.</typeparam>
/// <typeparam name="TUserLogin">The type representing a user external login.</typeparam>
/// <typeparam name="TUserToken">The type representing a user token.</typeparam>
public class UserOnlyStore<TUser, TContext, TKey, TUserClaim, TUserLogin, TUserToken> :
UserStoreBase<TUser, TKey, TUserClaim, TUserLogin, TUserToken>,
IUserLoginStore<TUser>,
IUserClaimStore<TUser>,
IUserPasswordStore<TUser>,
IUserSecurityStampStore<TUser>,
IUserEmailStore<TUser>,
IUserLockoutStore<TUser>,
IUserPhoneNumberStore<TUser>,
IQueryableUserStore<TUser>,
IUserTwoFactorStore<TUser>,
IUserAuthenticationTokenStore<TUser>,
IUserAuthenticatorKeyStore<TUser>,
IUserTwoFactorRecoveryCodeStore<TUser>
where TUser : IdentityUser<TKey>
where TContext : DbContext
where TKey : IEquatable<TKey>
where TUserClaim : IdentityUserClaim<TKey>, new()
where TUserLogin : IdentityUserLogin<TKey>, new()
where TUserToken : IdentityUserToken<TKey>, new()
{
/// <summary>
/// Creates a new instance of the store.
/// </summary>
/// <param name="context">The context used to access the store.</param>
/// <param name="describer">The <see cref="IdentityErrorDescriber"/> used to describe store errors.</param>
public UserOnlyStore(TContext context, IdentityErrorDescriber describer = null) : base(describer ?? new IdentityErrorDescriber())
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
Context = context;
}
/// <summary>
/// Gets the database context for this store.
/// </summary>
public TContext Context { get; private set; }
/// <summary>
/// DbSet of users.
/// </summary>
protected DbSet<TUser> UsersSet { get { return Context.Set<TUser>(); } }
/// <summary>
/// DbSet of user claims.
/// </summary>
protected DbSet<TUserClaim> UserClaims { get { return Context.Set<TUserClaim>(); } }
/// <summary>
/// DbSet of user logins.
/// </summary>
protected DbSet<TUserLogin> UserLogins { get { return Context.Set<TUserLogin>(); } }
/// <summary>
/// DbSet of user tokens.
/// </summary>
protected DbSet<TUserToken> UserTokens { get { return Context.Set<TUserToken>(); } }
/// <summary>
/// Gets or sets a flag indicating if changes should be persisted after CreateAsync, UpdateAsync and DeleteAsync are called.
/// </summary>
/// <value>
/// True if changes should be automatically persisted, otherwise false.
/// </value>
public bool AutoSaveChanges { get; set; } = true;
/// <summary>Saves the current store.</summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
protected Task SaveChanges(CancellationToken cancellationToken)
{
return AutoSaveChanges ? Context.SaveChangesAsync(cancellationToken) : Task.CompletedTask;
}
/// <summary>
/// Creates the specified <paramref name="user"/> in the user store.
/// </summary>
/// <param name="user">The user to create.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation, containing the <see cref="IdentityResult"/> of the creation operation.</returns>
public async override Task<IdentityResult> CreateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
Context.Add(user);
await SaveChanges(cancellationToken);
return IdentityResult.Success;
}
/// <summary>
/// Updates the specified <paramref name="user"/> in the user store.
/// </summary>
/// <param name="user">The user to update.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation, containing the <see cref="IdentityResult"/> of the update operation.</returns>
public async override Task<IdentityResult> UpdateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
Context.Attach(user);
user.ConcurrencyStamp = Guid.NewGuid().ToString();
Context.Update(user);
try
{
await SaveChanges(cancellationToken);
}
catch (DbUpdateConcurrencyException)
{
return IdentityResult.Failed(ErrorDescriber.ConcurrencyFailure());
}
return IdentityResult.Success;
}
/// <summary>
/// Deletes the specified <paramref name="user"/> from the user store.
/// </summary>
/// <param name="user">The user to delete.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation, containing the <see cref="IdentityResult"/> of the update operation.</returns>
public async override Task<IdentityResult> DeleteAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
Context.Remove(user);
try
{
await SaveChanges(cancellationToken);
}
catch (DbUpdateConcurrencyException)
{
return IdentityResult.Failed(ErrorDescriber.ConcurrencyFailure());
}
return IdentityResult.Success;
}
/// <summary>
/// Finds and returns a user, if any, who has the specified <paramref name="userId"/>.
/// </summary>
/// <param name="userId">The user ID to search for.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>
/// The <see cref="Task"/> that represents the asynchronous operation, containing the user matching the specified <paramref name="userId"/> if it exists.
/// </returns>
public override Task<TUser> FindByIdAsync(string userId, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
var id = ConvertIdFromString(userId);
return UsersSet.FindAsync(new object[] { id }, cancellationToken);
}
/// <summary>
/// Finds and returns a user, if any, who has the specified normalized user name.
/// </summary>
/// <param name="normalizedUserName">The normalized user name to search for.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>
/// The <see cref="Task"/> that represents the asynchronous operation, containing the user matching the specified <paramref name="normalizedUserName"/> if it exists.
/// </returns>
public override Task<TUser> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
return Users.FirstOrDefaultAsync(u => u.NormalizedUserName == normalizedUserName, cancellationToken);
}
/// <summary>
/// A navigation property for the users the store contains.
/// </summary>
public override IQueryable<TUser> Users
{
get { return UsersSet; }
}
/// <summary>
/// Return a user with the matching userId if it exists.
/// </summary>
/// <param name="userId">The user's id.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The user if it exists.</returns>
protected override Task<TUser> FindUserAsync(TKey userId, CancellationToken cancellationToken)
{
return Users.SingleOrDefaultAsync(u => u.Id.Equals(userId), cancellationToken);
}
/// <summary>
/// Return a user login with the matching userId, provider, providerKey if it exists.
/// </summary>
/// <param name="userId">The user's id.</param>
/// <param name="loginProvider">The login provider name.</param>
/// <param name="providerKey">The key provided by the <paramref name="loginProvider"/> to identify a user.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The user login if it exists.</returns>
protected override Task<TUserLogin> FindUserLoginAsync(TKey userId, string loginProvider, string providerKey, CancellationToken cancellationToken)
{
return UserLogins.SingleOrDefaultAsync(userLogin => userLogin.UserId.Equals(userId) && userLogin.LoginProvider == loginProvider && userLogin.ProviderKey == providerKey, cancellationToken);
}
/// <summary>
/// Return a user login with provider, providerKey if it exists.
/// </summary>
/// <param name="loginProvider">The login provider name.</param>
/// <param name="providerKey">The key provided by the <paramref name="loginProvider"/> to identify a user.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The user login if it exists.</returns>
protected override Task<TUserLogin> FindUserLoginAsync(string loginProvider, string providerKey, CancellationToken cancellationToken)
{
return UserLogins.SingleOrDefaultAsync(userLogin => userLogin.LoginProvider == loginProvider && userLogin.ProviderKey == providerKey, cancellationToken);
}
/// <summary>
/// Get the claims associated with the specified <paramref name="user"/> as an asynchronous operation.
/// </summary>
/// <param name="user">The user whose claims should be retrieved.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>A <see cref="Task{TResult}"/> that contains the claims granted to a user.</returns>
public async override Task<IList<Claim>> GetClaimsAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
return await UserClaims.Where(uc => uc.UserId.Equals(user.Id)).Select(c => c.ToClaim()).ToListAsync(cancellationToken);
}
/// <summary>
/// Adds the <paramref name="claims"/> given to the specified <paramref name="user"/>.
/// </summary>
/// <param name="user">The user to add the claim to.</param>
/// <param name="claims">The claim to add to the user.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
public override Task AddClaimsAsync(TUser user, IEnumerable<Claim> claims, CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
if (claims == null)
{
throw new ArgumentNullException(nameof(claims));
}
foreach (var claim in claims)
{
UserClaims.Add(CreateUserClaim(user, claim));
}
return Task.FromResult(false);
}
/// <summary>
/// Replaces the <paramref name="claim"/> on the specified <paramref name="user"/>, with the <paramref name="newClaim"/>.
/// </summary>
/// <param name="user">The user to replace the claim on.</param>
/// <param name="claim">The claim replace.</param>
/// <param name="newClaim">The new claim replacing the <paramref name="claim"/>.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
public async override Task ReplaceClaimAsync(TUser user, Claim claim, Claim newClaim, CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
if (claim == null)
{
throw new ArgumentNullException(nameof(claim));
}
if (newClaim == null)
{
throw new ArgumentNullException(nameof(newClaim));
}
var matchedClaims = await UserClaims.Where(uc => uc.UserId.Equals(user.Id) && uc.ClaimValue == claim.Value && uc.ClaimType == claim.Type).ToListAsync(cancellationToken);
foreach (var matchedClaim in matchedClaims)
{
matchedClaim.ClaimValue = newClaim.Value;
matchedClaim.ClaimType = newClaim.Type;
}
}
/// <summary>
/// Removes the <paramref name="claims"/> given from the specified <paramref name="user"/>.
/// </summary>
/// <param name="user">The user to remove the claims from.</param>
/// <param name="claims">The claim to remove.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
public async override Task RemoveClaimsAsync(TUser user, IEnumerable<Claim> claims, CancellationToken cancellationToken = default(CancellationToken))
{
ThrowIfDisposed();
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
if (claims == null)
{
throw new ArgumentNullException(nameof(claims));
}
foreach (var claim in claims)
{
var matchedClaims = await UserClaims.Where(uc => uc.UserId.Equals(user.Id) && uc.ClaimValue == claim.Value && uc.ClaimType == claim.Type).ToListAsync(cancellationToken);
foreach (var c in matchedClaims)
{
UserClaims.Remove(c);
}
}
}
/// <summary>
/// Adds the <paramref name="login"/> given to the specified <paramref name="user"/>.
/// </summary>
/// <param name="user">The user to add the login to.</param>
/// <param name="login">The login to add to the user.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
public override Task AddLoginAsync(TUser user, UserLoginInfo login,
CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
if (login == null)
{
throw new ArgumentNullException(nameof(login));
}
UserLogins.Add(CreateUserLogin(user, login));
return Task.FromResult(false);
}
/// <summary>
/// Removes the <paramref name="loginProvider"/> given from the specified <paramref name="user"/>.
/// </summary>
/// <param name="user">The user to remove the login from.</param>
/// <param name="loginProvider">The login to remove from the user.</param>
/// <param name="providerKey">The key provided by the <paramref name="loginProvider"/> to identify a user.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
public override async Task RemoveLoginAsync(TUser user, string loginProvider, string providerKey,
CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
var entry = await FindUserLoginAsync(user.Id, loginProvider, providerKey, cancellationToken);
if (entry != null)
{
UserLogins.Remove(entry);
}
}
/// <summary>
/// Retrieves the associated logins for the specified <param ref="user"/>.
/// </summary>
/// <param name="user">The user whose associated logins to retrieve.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>
/// The <see cref="Task"/> for the asynchronous operation, containing a list of <see cref="UserLoginInfo"/> for the specified <paramref name="user"/>, if any.
/// </returns>
public async override Task<IList<UserLoginInfo>> GetLoginsAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
var userId = user.Id;
return await UserLogins.Where(l => l.UserId.Equals(userId))
.Select(l => new UserLoginInfo(l.LoginProvider, l.ProviderKey, l.ProviderDisplayName)).ToListAsync(cancellationToken);
}
/// <summary>
/// Retrieves the user associated with the specified login provider and login provider key.
/// </summary>
/// <param name="loginProvider">The login provider who provided the <paramref name="providerKey"/>.</param>
/// <param name="providerKey">The key provided by the <paramref name="loginProvider"/> to identify a user.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>
/// The <see cref="Task"/> for the asynchronous operation, containing the user, if any which matched the specified login provider and key.
/// </returns>
public async override Task<TUser> FindByLoginAsync(string loginProvider, string providerKey,
CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
var userLogin = await FindUserLoginAsync(loginProvider, providerKey, cancellationToken);
if (userLogin != null)
{
return await FindUserAsync(userLogin.UserId, cancellationToken);
}
return null;
}
/// <summary>
/// Gets the user, if any, associated with the specified, normalized email address.
/// </summary>
/// <param name="normalizedEmail">The normalized email address to return the user for.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>
/// The task object containing the results of the asynchronous lookup operation, the user if any associated with the specified normalized email address.
/// </returns>
public override Task<TUser> FindByEmailAsync(string normalizedEmail, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
return Users.FirstOrDefaultAsync(u => u.NormalizedEmail == normalizedEmail, cancellationToken);
}
/// <summary>
/// Retrieves all users with the specified claim.
/// </summary>
/// <param name="claim">The claim whose users should be retrieved.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>
/// The <see cref="Task"/> contains a list of users, if any, that contain the specified claim.
/// </returns>
public async override Task<IList<TUser>> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken = default(CancellationToken))
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
if (claim == null)
{
throw new ArgumentNullException(nameof(claim));
}
var query = from userclaims in UserClaims
join user in Users on userclaims.UserId equals user.Id
where userclaims.ClaimValue == claim.Value
&& userclaims.ClaimType == claim.Type
select user;
return await query.ToListAsync(cancellationToken);
}
/// <summary>
/// Find a user token if it exists.
/// </summary>
/// <param name="user">The token owner.</param>
/// <param name="loginProvider">The login provider for the token.</param>
/// <param name="name">The name of the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The user token if it exists.</returns>
protected override Task<TUserToken> FindTokenAsync(TUser user, string loginProvider, string name, CancellationToken cancellationToken)
=> UserTokens.FindAsync(new object[] { user.Id, loginProvider, name }, cancellationToken);
/// <summary>
/// Add a new user token.
/// </summary>
/// <param name="token">The token to be added.</param>
/// <returns></returns>
protected override Task AddUserTokenAsync(TUserToken token)
{
UserTokens.Add(token);
return Task.CompletedTask;
}
/// <summary>
/// Remove a new user token.
/// </summary>
/// <param name="token">The token to be removed.</param>
/// <returns></returns>
protected override Task RemoveUserTokenAsync(TUserToken token)
{
UserTokens.Remove(token);
return Task.CompletedTask;
}
}
}

View File

@ -9,7 +9,6 @@ using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
{
@ -95,22 +94,9 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// <typeparam name="TUserToken">The type representing a user token.</typeparam>
/// <typeparam name="TRoleClaim">The type representing a role claim.</typeparam>
public class UserStore<TUser, TRole, TContext, TKey, TUserClaim, TUserRole, TUserLogin, TUserToken, TRoleClaim> :
UserStoreBase<TUser, TRole, TKey, TUserClaim, TUserRole, TUserLogin, TUserToken, TRoleClaim>,
IUserLoginStore<TUser>,
IUserRoleStore<TUser>,
IUserClaimStore<TUser>,
IUserPasswordStore<TUser>,
IUserSecurityStampStore<TUser>,
IUserEmailStore<TUser>,
IUserLockoutStore<TUser>,
IUserPhoneNumberStore<TUser>,
IQueryableUserStore<TUser>,
IUserTwoFactorStore<TUser>,
IUserAuthenticationTokenStore<TUser>,
IUserAuthenticatorKeyStore<TUser>,
IUserTwoFactorRecoveryCodeStore<TUser>
where TUser : IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin, TUserToken>
where TRole : IdentityRole<TKey, TUserRole, TRoleClaim>
UserStoreBase<TUser, TRole, TKey, TUserClaim, TUserRole, TUserLogin, TUserToken, TRoleClaim>
where TUser : IdentityUser<TKey>
where TRole : IdentityRole<TKey>
where TContext : DbContext
where TKey : IEquatable<TKey>
where TUserClaim : IdentityUserClaim<TKey>, new()

View File

@ -54,8 +54,8 @@ namespace Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore
TRedirectUri,
TApplicationKey> :
IdentityDbContext<TUser, TRole, TUserKey, TUserClaim, TUserRole, TUserLogin, TRoleClaim, TUserToken>
where TUser : IdentityUser<TUserKey, TUserClaim, TUserRole, TUserLogin, TUserToken>
where TRole : IdentityRole<TUserKey, TUserRole, TRoleClaim>
where TUser : IdentityUser<TUserKey>
where TRole : IdentityRole<TUserKey>
where TUserKey : IEquatable<TUserKey>
where TUserClaim : IdentityUserClaim<TUserKey>
where TUserRole : IdentityUserRole<TUserKey>

View File

@ -1,119 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Text;
namespace Microsoft.AspNetCore.Identity
{
// See http://tools.ietf.org/html/rfc3548#section-5
internal static class Base32
{
private static readonly string _base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
public static string ToBase32(byte[] input)
{
if (input == null)
{
throw new ArgumentNullException(nameof(input));
}
StringBuilder sb = new StringBuilder();
for (int offset = 0; offset < input.Length;)
{
byte a, b, c, d, e, f, g, h;
int numCharsToOutput = GetNextGroup(input, ref offset, out a, out b, out c, out d, out e, out f, out g, out h);
sb.Append((numCharsToOutput >= 1) ? _base32Chars[a] : '=');
sb.Append((numCharsToOutput >= 2) ? _base32Chars[b] : '=');
sb.Append((numCharsToOutput >= 3) ? _base32Chars[c] : '=');
sb.Append((numCharsToOutput >= 4) ? _base32Chars[d] : '=');
sb.Append((numCharsToOutput >= 5) ? _base32Chars[e] : '=');
sb.Append((numCharsToOutput >= 6) ? _base32Chars[f] : '=');
sb.Append((numCharsToOutput >= 7) ? _base32Chars[g] : '=');
sb.Append((numCharsToOutput >= 8) ? _base32Chars[h] : '=');
}
return sb.ToString();
}
public static byte[] FromBase32(string input)
{
if (input == null)
{
throw new ArgumentNullException(nameof(input));
}
input = input.TrimEnd('=').ToUpperInvariant();
if (input.Length == 0)
{
return new byte[0];
}
var output = new byte[input.Length * 5 / 8];
var bitIndex = 0;
var inputIndex = 0;
var outputBits = 0;
var outputIndex = 0;
while (outputIndex < output.Length)
{
var byteIndex = _base32Chars.IndexOf(input[inputIndex]);
if (byteIndex < 0)
{
throw new FormatException();
}
var bits = Math.Min(5 - bitIndex, 8 - outputBits);
output[outputIndex] <<= bits;
output[outputIndex] |= (byte)(byteIndex >> (5 - (bitIndex + bits)));
bitIndex += bits;
if (bitIndex >= 5)
{
inputIndex++;
bitIndex = 0;
}
outputBits += bits;
if (outputBits >= 8)
{
outputIndex++;
outputBits = 0;
}
}
return output;
}
// returns the number of bytes that were output
private static int GetNextGroup(byte[] input, ref int offset, out byte a, out byte b, out byte c, out byte d, out byte e, out byte f, out byte g, out byte h)
{
uint b1, b2, b3, b4, b5;
int retVal;
switch (offset - input.Length)
{
case 1: retVal = 2; break;
case 2: retVal = 4; break;
case 3: retVal = 5; break;
case 4: retVal = 7; break;
default: retVal = 8; break;
}
b1 = (offset < input.Length) ? input[offset++] : 0U;
b2 = (offset < input.Length) ? input[offset++] : 0U;
b3 = (offset < input.Length) ? input[offset++] : 0U;
b4 = (offset < input.Length) ? input[offset++] : 0U;
b5 = (offset < input.Length) ? input[offset++] : 0U;
a = (byte)(b1 >> 3);
b = (byte)(((b1 & 0x07) << 2) | (b2 >> 6));
c = (byte)((b2 >> 1) & 0x1f);
d = (byte)(((b2 & 0x01) << 4) | (b3 >> 4));
e = (byte)(((b3 & 0x0f) << 1) | (b4 >> 7));
f = (byte)((b4 >> 2) & 0x1f);
g = (byte)(((b4 & 0x3) << 3) | (b5 >> 5));
h = (byte)(b5 & 0x1f);
return retVal;
}
}
}

View File

@ -0,0 +1,57 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Identity
{
/// <summary>
/// Helper functions for configuring identity services.
/// </summary>
public static class IdentityBuilderExtensions
{
/// <summary>
/// Adds the default token providers used to generate tokens for reset passwords, change email
/// and change telephone number operations, and for two factor authentication token generation.
/// </summary>
/// <param name="builder">The current <see cref="IdentityBuilder"/> instance.</param>
/// <returns>The current <see cref="IdentityBuilder"/> instance.</returns>
public static IdentityBuilder AddDefaultTokenProviders(this IdentityBuilder builder)
{
var userType = builder.UserType;
var dataProtectionProviderType = typeof(DataProtectorTokenProvider<>).MakeGenericType(userType);
var phoneNumberProviderType = typeof(PhoneNumberTokenProvider<>).MakeGenericType(userType);
var emailTokenProviderType = typeof(EmailTokenProvider<>).MakeGenericType(userType);
var authenticatorProviderType = typeof(AuthenticatorTokenProvider<>).MakeGenericType(userType);
return builder.AddTokenProvider(TokenOptions.DefaultProvider, dataProtectionProviderType)
.AddTokenProvider(TokenOptions.DefaultEmailProvider, emailTokenProviderType)
.AddTokenProvider(TokenOptions.DefaultPhoneProvider, phoneNumberProviderType)
.AddTokenProvider(TokenOptions.DefaultAuthenticatorProvider, authenticatorProviderType);
}
/// <summary>
/// Adds a <see cref="SignInManager{TUser}"/> for the <seealso cref="IdentityBuilder.UserType"/>.
/// </summary>
/// <typeparam name="TSignInManager">The type of the sign in manager to add.</typeparam>
/// <param name="builder">The current <see cref="IdentityBuilder"/> instance.</param>
/// <returns>The current <see cref="IdentityBuilder"/> instance.</returns>
public static IdentityBuilder AddSignInManager<TSignInManager>(this IdentityBuilder builder) where TSignInManager : class
{
var managerType = typeof(SignInManager<>).MakeGenericType(builder.UserType);
var customType = typeof(TSignInManager);
if (!managerType.GetTypeInfo().IsAssignableFrom(customType.GetTypeInfo()))
{
throw new InvalidOperationException(Resources.FormatInvalidManagerType(customType.Name, "SignInManager", builder.UserType.Name));
}
if (managerType != customType)
{
builder.Services.AddScoped(typeof(TSignInManager), services => services.GetRequiredService(managerType));
}
builder.Services.AddScoped(managerType, typeof(TSignInManager));
return builder;
}
}
}

View File

@ -5,58 +5,52 @@ namespace Microsoft.AspNetCore.Identity
using System.Reflection;
using System.Resources;
internal static class AspNetIdentityResources
internal static class Resources
{
private static readonly ResourceManager _resourceManager
= new ResourceManager("Microsoft.AspNetCore.Identity.Resources", typeof(AspNetIdentityResources).GetTypeInfo().Assembly);
= new ResourceManager("Microsoft.AspNetCore.Identity.Resources", typeof(Resources).GetTypeInfo().Assembly);
/// <summary>
/// Type {0} must derive from {1}&lt;{2}&gt;.
/// </summary>
internal static string InvalidManagerType
{
get { return GetString("InvalidManagerType"); }
get => GetString("InvalidManagerType");
}
/// <summary>
/// Type {0} must derive from {1}&lt;{2}&gt;.
/// </summary>
internal static string FormatInvalidManagerType(object p0, object p1, object p2)
{
return string.Format(CultureInfo.CurrentCulture, GetString("InvalidManagerType"), p0, p1, p2);
}
=> string.Format(CultureInfo.CurrentCulture, GetString("InvalidManagerType"), p0, p1, p2);
/// <summary>
/// The provided PasswordHasherCompatibilityMode is invalid.
/// </summary>
internal static string InvalidPasswordHasherCompatibilityMode
{
get { return GetString("InvalidPasswordHasherCompatibilityMode"); }
get => GetString("InvalidPasswordHasherCompatibilityMode");
}
/// <summary>
/// The provided PasswordHasherCompatibilityMode is invalid.
/// </summary>
internal static string FormatInvalidPasswordHasherCompatibilityMode()
{
return GetString("InvalidPasswordHasherCompatibilityMode");
}
=> GetString("InvalidPasswordHasherCompatibilityMode");
/// <summary>
/// The iteration count must be a positive integer.
/// </summary>
internal static string InvalidPasswordHasherIterationCount
{
get { return GetString("InvalidPasswordHasherIterationCount"); }
get => GetString("InvalidPasswordHasherIterationCount");
}
/// <summary>
/// The iteration count must be a positive integer.
/// </summary>
internal static string FormatInvalidPasswordHasherIterationCount()
{
return GetString("InvalidPasswordHasherIterationCount");
}
=> GetString("InvalidPasswordHasherIterationCount");
private static string GetString(string name, params string[] formatterNames)
{

View File

@ -5,6 +5,8 @@ using System;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Identity.Core;
namespace Microsoft.AspNetCore.Identity
{
@ -17,15 +19,22 @@ namespace Microsoft.AspNetCore.Identity
/// Creates a new instance of <see cref="IdentityBuilder"/>.
/// </summary>
/// <param name="user">The <see cref="Type"/> to use for the users.</param>
/// <param name="role">The <see cref="Type"/> to use for the roles.</param>
/// <param name="services">The <see cref="IServiceCollection"/> to attach to.</param>
public IdentityBuilder(Type user, Type role, IServiceCollection services)
public IdentityBuilder(Type user, IServiceCollection services)
{
UserType = user;
RoleType = role;
Services = services;
}
/// <summary>
/// Creates a new instance of <see cref="IdentityBuilder"/>.
/// </summary>
/// <param name="user">The <see cref="Type"/> to use for the users.</param>
/// <param name="role">The <see cref="Type"/> to use for the roles.</param>
/// <param name="services">The <see cref="IServiceCollection"/> to attach to.</param>
public IdentityBuilder(Type user, Type role, IServiceCollection services) : this(user, services)
=> RoleType = role;
/// <summary>
/// Gets the <see cref="Type"/> used for users.
/// </summary>
@ -60,32 +69,18 @@ namespace Microsoft.AspNetCore.Identity
/// <summary>
/// Adds an <see cref="IUserValidator{TUser}"/> for the <seealso cref="UserType"/>.
/// </summary>
/// <typeparam name="T">The user validator type.</typeparam>
/// <typeparam name="TUser">The user validator type.</typeparam>
/// <returns>The current <see cref="IdentityBuilder"/> instance.</returns>
public virtual IdentityBuilder AddUserValidator<T>() where T : class
{
return AddScoped(typeof(IUserValidator<>).MakeGenericType(UserType), typeof(T));
}
/// <summary>
/// Adds an <see cref="IRoleValidator{TRole}"/> for the <seealso cref="RoleType"/>.
/// </summary>
/// <typeparam name="T">The role validator type.</typeparam>
/// <returns>The current <see cref="IdentityBuilder"/> instance.</returns>
public virtual IdentityBuilder AddRoleValidator<T>() where T : class
{
return AddScoped(typeof(IRoleValidator<>).MakeGenericType(RoleType), typeof(T));
}
public virtual IdentityBuilder AddUserValidator<TUser>() where TUser : class
=> AddScoped(typeof(IUserValidator<>).MakeGenericType(UserType), typeof(TUser));
/// <summary>
/// Adds an <see cref="IUserClaimsPrincipalFactory{TUser}"/> for the <seealso cref="UserType"/>.
/// </summary>
/// <typeparam name="T">The type of the claims principal factory.</typeparam>
/// <typeparam name="TUser">The type of the claims principal factory.</typeparam>
/// <returns>The current <see cref="IdentityBuilder"/> instance.</returns>
public virtual IdentityBuilder AddClaimsPrincipalFactory<T>() where T : class
{
return AddScoped(typeof(IUserClaimsPrincipalFactory<>).MakeGenericType(UserType), typeof(T));
}
public virtual IdentityBuilder AddClaimsPrincipalFactory<TUser>() where TUser : class
=> AddScoped(typeof(IUserClaimsPrincipalFactory<>).MakeGenericType(UserType), typeof(TUser));
/// <summary>
/// Adds an <see cref="IdentityErrorDescriber"/>.
@ -101,32 +96,18 @@ namespace Microsoft.AspNetCore.Identity
/// <summary>
/// Adds an <see cref="IPasswordValidator{TUser}"/> for the <seealso cref="UserType"/>.
/// </summary>
/// <typeparam name="T">The user type whose password will be validated.</typeparam>
/// <typeparam name="TUser">The user type whose password will be validated.</typeparam>
/// <returns>The current <see cref="IdentityBuilder"/> instance.</returns>
public virtual IdentityBuilder AddPasswordValidator<T>() where T : class
{
return AddScoped(typeof(IPasswordValidator<>).MakeGenericType(UserType), typeof(T));
}
public virtual IdentityBuilder AddPasswordValidator<TUser>() where TUser : class
=> AddScoped(typeof(IPasswordValidator<>).MakeGenericType(UserType), typeof(TUser));
/// <summary>
/// Adds an <see cref="IUserStore{TUser}"/> for the <seealso cref="UserType"/>.
/// </summary>
/// <typeparam name="T">The user type held in the store.</typeparam>
/// <typeparam name="TUser">The user type held in the store.</typeparam>
/// <returns>The current <see cref="IdentityBuilder"/> instance.</returns>
public virtual IdentityBuilder AddUserStore<T>() where T : class
{
return AddScoped(typeof(IUserStore<>).MakeGenericType(UserType), typeof(T));
}
/// <summary>
/// Adds a <see cref="IRoleStore{TRole}"/> for the <seealso cref="RoleType"/>.
/// </summary>
/// <typeparam name="T">The role type held in the store.</typeparam>
/// <returns>The current <see cref="IdentityBuilder"/> instance.</returns>
public virtual IdentityBuilder AddRoleStore<T>() where T : class
{
return AddScoped(typeof(IRoleStore<>).MakeGenericType(RoleType), typeof(T));
}
public virtual IdentityBuilder AddUserStore<TUser>() where TUser : class
=> AddScoped(typeof(IUserStore<>).MakeGenericType(UserType), typeof(TUser));
/// <summary>
/// Adds a token provider.
@ -135,9 +116,7 @@ namespace Microsoft.AspNetCore.Identity
/// <param name="providerName">The name of the provider to add.</param>
/// <returns>The current <see cref="IdentityBuilder"/> instance.</returns>
public virtual IdentityBuilder AddTokenProvider<TProvider>(string providerName) where TProvider : class
{
return AddTokenProvider(providerName, typeof(TProvider));
}
=> AddTokenProvider(providerName, typeof(TProvider));
/// <summary>
/// Adds a token provider for the <seealso cref="UserType"/>.
@ -149,7 +128,7 @@ namespace Microsoft.AspNetCore.Identity
{
if (!typeof(IUserTwoFactorTokenProvider<>).MakeGenericType(UserType).GetTypeInfo().IsAssignableFrom(provider.GetTypeInfo()))
{
throw new InvalidOperationException(AspNetIdentityResources.FormatInvalidManagerType(provider.Name, "IUserTokenProvider", UserType.Name));
throw new InvalidOperationException(Resources.FormatInvalidManagerType(provider.Name, "IUserTokenProvider", UserType.Name));
}
Services.Configure<IdentityOptions>(options =>
{
@ -159,23 +138,6 @@ namespace Microsoft.AspNetCore.Identity
return this;
}
/// <summary>
/// Adds the default token providers used to generate tokens for reset passwords, change email
/// and change telephone number operations, and for two factor authentication token generation.
/// </summary>
/// <returns>The current <see cref="IdentityBuilder"/> instance.</returns>
public virtual IdentityBuilder AddDefaultTokenProviders()
{
var dataProtectionProviderType = typeof(DataProtectorTokenProvider<>).MakeGenericType(UserType);
var phoneNumberProviderType = typeof(PhoneNumberTokenProvider<>).MakeGenericType(UserType);
var emailTokenProviderType = typeof(EmailTokenProvider<>).MakeGenericType(UserType);
var authenticatorProviderType = typeof(AuthenticatorTokenProvider<>).MakeGenericType(UserType);
return AddTokenProvider(TokenOptions.DefaultProvider, dataProtectionProviderType)
.AddTokenProvider(TokenOptions.DefaultEmailProvider, emailTokenProviderType)
.AddTokenProvider(TokenOptions.DefaultPhoneProvider, phoneNumberProviderType)
.AddTokenProvider(TokenOptions.DefaultAuthenticatorProvider, authenticatorProviderType);
}
/// <summary>
/// Adds a <see cref="UserManager{TUser}"/> for the <seealso cref="UserType"/>.
/// </summary>
@ -185,15 +147,60 @@ namespace Microsoft.AspNetCore.Identity
{
var userManagerType = typeof(UserManager<>).MakeGenericType(UserType);
var customType = typeof(TUserManager);
if (userManagerType == customType ||
!userManagerType.GetTypeInfo().IsAssignableFrom(customType.GetTypeInfo()))
if (!userManagerType.GetTypeInfo().IsAssignableFrom(customType.GetTypeInfo()))
{
throw new InvalidOperationException(AspNetIdentityResources.FormatInvalidManagerType(customType.Name, "UserManager", UserType.Name));
throw new InvalidOperationException(Resources.FormatInvalidManagerType(customType.Name, "UserManager", UserType.Name));
}
if (userManagerType != customType)
{
Services.AddScoped(customType, services => services.GetRequiredService(userManagerType));
}
Services.AddScoped(customType, services => services.GetRequiredService(userManagerType));
return AddScoped(userManagerType, customType);
}
/// <summary>
/// Adds Role related services for TRole, including IRoleStore, IRoleValidator, and RoleManager.
/// </summary>
/// <typeparam name="TRole">The role type.</typeparam>
/// <returns>The current <see cref="IdentityBuilder"/> instance.</returns>
public virtual IdentityBuilder AddRoles<TRole>() where TRole : class
{
RoleType = typeof(TRole);
AddRoleStore<TRole>();
AddRoleValidator<RoleValidator<TRole>>();
Services.TryAddScoped<RoleManager<TRole>, RoleManager<TRole>>();
return this;
}
/// <summary>
/// Adds an <see cref="IRoleValidator{TRole}"/> for the <seealso cref="RoleType"/>.
/// </summary>
/// <typeparam name="TRole">The role validator type.</typeparam>
/// <returns>The current <see cref="IdentityBuilder"/> instance.</returns>
public virtual IdentityBuilder AddRoleValidator<TRole>() where TRole : class
{
if (RoleType == null)
{
throw new InvalidOperationException(Resources.NoRoleType);
}
return AddScoped(typeof(IRoleValidator<>).MakeGenericType(RoleType), typeof(TRole));
}
/// <summary>
/// Adds a <see cref="IRoleStore{TRole}"/> for the <seealso cref="RoleType"/>.
/// </summary>
/// <typeparam name="TRole">The role type held in the store.</typeparam>
/// <returns>The current <see cref="IdentityBuilder"/> instance.</returns>
public virtual IdentityBuilder AddRoleStore<TRole>() where TRole : class
{
if (RoleType == null)
{
throw new InvalidOperationException(Resources.NoRoleType);
}
return AddScoped(typeof(IRoleStore<>).MakeGenericType(RoleType), typeof(TRole));
}
/// <summary>
/// Adds a <see cref="RoleManager{TRole}"/> for the <seealso cref="RoleType"/>.
/// </summary>
@ -201,33 +208,21 @@ namespace Microsoft.AspNetCore.Identity
/// <returns>The current <see cref="IdentityBuilder"/> instance.</returns>
public virtual IdentityBuilder AddRoleManager<TRoleManager>() where TRoleManager : class
{
if (RoleType == null)
{
throw new InvalidOperationException(Resources.NoRoleType);
}
var managerType = typeof(RoleManager<>).MakeGenericType(RoleType);
var customType = typeof(TRoleManager);
if (managerType == customType ||
!managerType.GetTypeInfo().IsAssignableFrom(customType.GetTypeInfo()))
if (!managerType.GetTypeInfo().IsAssignableFrom(customType.GetTypeInfo()))
{
throw new InvalidOperationException(AspNetIdentityResources.FormatInvalidManagerType(customType.Name, "RoleManager", RoleType.Name));
throw new InvalidOperationException(Resources.FormatInvalidManagerType(customType.Name, "RoleManager", RoleType.Name));
}
if (managerType != customType)
{
Services.AddScoped(typeof(TRoleManager), services => services.GetRequiredService(managerType));
}
Services.AddScoped(typeof(TRoleManager), services => services.GetRequiredService(managerType));
return AddScoped(managerType, typeof(TRoleManager));
}
/// <summary>
/// Adds a <see cref="SignInManager{TUser}"/> for the <seealso cref="UserType"/>.
/// </summary>
/// <typeparam name="TSignInManager">The type of the sign in manager to add.</typeparam>
/// <returns>The current <see cref="IdentityBuilder"/> instance.</returns>
public virtual IdentityBuilder AddSignInManager<TSignInManager>() where TSignInManager : class
{
var managerType = typeof(SignInManager<>).MakeGenericType(UserType);
var customType = typeof(TSignInManager);
if (managerType == customType ||
!managerType.GetTypeInfo().IsAssignableFrom(customType.GetTypeInfo()))
{
throw new InvalidOperationException(AspNetIdentityResources.FormatInvalidManagerType(customType.Name, "SignInManager", UserType.Name));
}
Services.AddScoped(typeof(TSignInManager), services => services.GetRequiredService(managerType));
return AddScoped(managerType, typeof(TSignInManager));
}
}
}

View File

@ -1,6 +1,8 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Extensions.Identity.Core;
namespace Microsoft.AspNetCore.Identity
{
/// <summary>

View File

@ -0,0 +1,47 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Microsoft.Extensions.DependencyInjection
{
/// <summary>
/// Contains extension methods to <see cref="IServiceCollection"/> for configuring identity services.
/// </summary>
public static class IdentityServiceCollectionExtensions
{
/// <summary>
/// Adds and configures the identity system for the specified User and Role types.
/// </summary>
/// <typeparam name="TUser">The type representing a User in the system.</typeparam>
/// <param name="services">The services available in the application.</param>
/// <param name="setupAction">An action to configure the <see cref="IdentityOptions"/>.</param>
/// <returns>An <see cref="IdentityBuilder"/> for creating and configuring the identity system.</returns>
public static IdentityBuilder AddIdentityCore<TUser>(this IServiceCollection services, Action<IdentityOptions> setupAction)
where TUser : class
{
// Services identity depends on
services.AddOptions().AddLogging();
// Services used by identity
services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>();
services.TryAddScoped<IPasswordValidator<TUser>, PasswordValidator<TUser>>();
services.TryAddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>();
services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
// No interface for the error describer so we can add errors without rev'ing the interface
services.TryAddScoped<IdentityErrorDescriber>();
services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser>>();
services.TryAddScoped<UserManager<TUser>, UserManager<TUser>>();
if (setupAction != null)
{
services.Configure(setupAction);
}
return new IdentityBuilder(typeof(TUser), services);
}
}
}

View File

@ -11,6 +11,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Options" Version="$(AspNetCoreVersion)" />
<PackageReference Include="System.ComponentModel.Annotations" Version="$(CoreFxVersion)" />

View File

@ -5,6 +5,7 @@ using System;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
using Microsoft.Extensions.Identity.Core;
using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Identity
@ -53,12 +54,12 @@ namespace Microsoft.AspNetCore.Identity
_iterCount = options.IterationCount;
if (_iterCount < 1)
{
throw new InvalidOperationException(AspNetIdentityResources.InvalidPasswordHasherIterationCount);
throw new InvalidOperationException(Resources.InvalidPasswordHasherIterationCount);
}
break;
default:
throw new InvalidOperationException(AspNetIdentityResources.InvalidPasswordHasherCompatibilityMode);
throw new InvalidOperationException(Resources.InvalidPasswordHasherCompatibilityMode);
}
_rng = options.Rng;

View File

@ -1,5 +1,5 @@
// <auto-generated />
namespace Microsoft.AspNetCore.Identity
namespace Microsoft.Extensions.Identity.Core
{
using System.Globalization;
using System.Reflection;
@ -15,753 +15,673 @@ namespace Microsoft.AspNetCore.Identity
/// </summary>
internal static string ConcurrencyFailure
{
get { return GetString("ConcurrencyFailure"); }
get => GetString("ConcurrencyFailure");
}
/// <summary>
/// Optimistic concurrency failure, object has been modified.
/// </summary>
internal static string FormatConcurrencyFailure()
{
return GetString("ConcurrencyFailure");
}
=> GetString("ConcurrencyFailure");
/// <summary>
/// An unknown failure has occurred.
/// </summary>
internal static string DefaultError
{
get { return GetString("DefaultError"); }
get => GetString("DefaultError");
}
/// <summary>
/// An unknown failure has occurred.
/// </summary>
internal static string FormatDefaultError()
{
return GetString("DefaultError");
}
=> GetString("DefaultError");
/// <summary>
/// Email '{0}' is already taken.
/// </summary>
internal static string DuplicateEmail
{
get { return GetString("DuplicateEmail"); }
get => GetString("DuplicateEmail");
}
/// <summary>
/// Email '{0}' is already taken.
/// </summary>
internal static string FormatDuplicateEmail(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("DuplicateEmail"), p0);
}
=> string.Format(CultureInfo.CurrentCulture, GetString("DuplicateEmail"), p0);
/// <summary>
/// Role name '{0}' is already taken.
/// </summary>
internal static string DuplicateRoleName
{
get { return GetString("DuplicateRoleName"); }
get => GetString("DuplicateRoleName");
}
/// <summary>
/// Role name '{0}' is already taken.
/// </summary>
internal static string FormatDuplicateRoleName(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("DuplicateRoleName"), p0);
}
=> string.Format(CultureInfo.CurrentCulture, GetString("DuplicateRoleName"), p0);
/// <summary>
/// User name '{0}' is already taken.
/// </summary>
internal static string DuplicateUserName
{
get { return GetString("DuplicateUserName"); }
get => GetString("DuplicateUserName");
}
/// <summary>
/// User name '{0}' is already taken.
/// </summary>
internal static string FormatDuplicateUserName(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("DuplicateUserName"), p0);
}
=> string.Format(CultureInfo.CurrentCulture, GetString("DuplicateUserName"), p0);
/// <summary>
/// Email '{0}' is invalid.
/// </summary>
internal static string InvalidEmail
{
get { return GetString("InvalidEmail"); }
get => GetString("InvalidEmail");
}
/// <summary>
/// Email '{0}' is invalid.
/// </summary>
internal static string FormatInvalidEmail(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("InvalidEmail"), p0);
}
=> string.Format(CultureInfo.CurrentCulture, GetString("InvalidEmail"), p0);
/// <summary>
/// Type {0} must derive from {1}&lt;{2}&gt;.
/// </summary>
internal static string InvalidManagerType
{
get { return GetString("InvalidManagerType"); }
get => GetString("InvalidManagerType");
}
/// <summary>
/// Type {0} must derive from {1}&lt;{2}&gt;.
/// </summary>
internal static string FormatInvalidManagerType(object p0, object p1, object p2)
{
return string.Format(CultureInfo.CurrentCulture, GetString("InvalidManagerType"), p0, p1, p2);
}
=> string.Format(CultureInfo.CurrentCulture, GetString("InvalidManagerType"), p0, p1, p2);
/// <summary>
/// The provided PasswordHasherCompatibilityMode is invalid.
/// </summary>
internal static string InvalidPasswordHasherCompatibilityMode
{
get { return GetString("InvalidPasswordHasherCompatibilityMode"); }
get => GetString("InvalidPasswordHasherCompatibilityMode");
}
/// <summary>
/// The provided PasswordHasherCompatibilityMode is invalid.
/// </summary>
internal static string FormatInvalidPasswordHasherCompatibilityMode()
{
return GetString("InvalidPasswordHasherCompatibilityMode");
}
=> GetString("InvalidPasswordHasherCompatibilityMode");
/// <summary>
/// The iteration count must be a positive integer.
/// </summary>
internal static string InvalidPasswordHasherIterationCount
{
get { return GetString("InvalidPasswordHasherIterationCount"); }
get => GetString("InvalidPasswordHasherIterationCount");
}
/// <summary>
/// The iteration count must be a positive integer.
/// </summary>
internal static string FormatInvalidPasswordHasherIterationCount()
{
return GetString("InvalidPasswordHasherIterationCount");
}
=> GetString("InvalidPasswordHasherIterationCount");
/// <summary>
/// Role name '{0}' is invalid.
/// </summary>
internal static string InvalidRoleName
{
get { return GetString("InvalidRoleName"); }
get => GetString("InvalidRoleName");
}
/// <summary>
/// Role name '{0}' is invalid.
/// </summary>
internal static string FormatInvalidRoleName(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("InvalidRoleName"), p0);
}
=> string.Format(CultureInfo.CurrentCulture, GetString("InvalidRoleName"), p0);
/// <summary>
/// Invalid token.
/// </summary>
internal static string InvalidToken
{
get { return GetString("InvalidToken"); }
get => GetString("InvalidToken");
}
/// <summary>
/// Invalid token.
/// </summary>
internal static string FormatInvalidToken()
{
return GetString("InvalidToken");
}
=> GetString("InvalidToken");
/// <summary>
/// User name '{0}' is invalid, can only contain letters or digits.
/// </summary>
internal static string InvalidUserName
{
get { return GetString("InvalidUserName"); }
get => GetString("InvalidUserName");
}
/// <summary>
/// User name '{0}' is invalid, can only contain letters or digits.
/// </summary>
internal static string FormatInvalidUserName(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("InvalidUserName"), p0);
}
=> string.Format(CultureInfo.CurrentCulture, GetString("InvalidUserName"), p0);
/// <summary>
/// A user with this login already exists.
/// </summary>
internal static string LoginAlreadyAssociated
{
get { return GetString("LoginAlreadyAssociated"); }
get => GetString("LoginAlreadyAssociated");
}
/// <summary>
/// A user with this login already exists.
/// </summary>
internal static string FormatLoginAlreadyAssociated()
{
return GetString("LoginAlreadyAssociated");
}
=> GetString("LoginAlreadyAssociated");
/// <summary>
/// AddIdentity must be called on the service collection.
/// </summary>
internal static string MustCallAddIdentity
{
get { return GetString("MustCallAddIdentity"); }
get => GetString("MustCallAddIdentity");
}
/// <summary>
/// AddIdentity must be called on the service collection.
/// </summary>
internal static string FormatMustCallAddIdentity()
{
return GetString("MustCallAddIdentity");
}
=> GetString("MustCallAddIdentity");
/// <summary>
/// No IUserTokenProvider named '{0}' is registered.
/// </summary>
internal static string NoTokenProvider
{
get { return GetString("NoTokenProvider"); }
get => GetString("NoTokenProvider");
}
/// <summary>
/// No IUserTokenProvider named '{0}' is registered.
/// </summary>
internal static string FormatNoTokenProvider(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("NoTokenProvider"), p0);
}
=> string.Format(CultureInfo.CurrentCulture, GetString("NoTokenProvider"), p0);
/// <summary>
/// User security stamp cannot be null.
/// </summary>
internal static string NullSecurityStamp
{
get { return GetString("NullSecurityStamp"); }
get => GetString("NullSecurityStamp");
}
/// <summary>
/// User security stamp cannot be null.
/// </summary>
internal static string FormatNullSecurityStamp()
{
return GetString("NullSecurityStamp");
}
=> GetString("NullSecurityStamp");
/// <summary>
/// Incorrect password.
/// </summary>
internal static string PasswordMismatch
{
get { return GetString("PasswordMismatch"); }
get => GetString("PasswordMismatch");
}
/// <summary>
/// Incorrect password.
/// </summary>
internal static string FormatPasswordMismatch()
{
return GetString("PasswordMismatch");
}
=> GetString("PasswordMismatch");
/// <summary>
/// Passwords must have at least one digit ('0'-'9').
/// </summary>
internal static string PasswordRequiresDigit
{
get { return GetString("PasswordRequiresDigit"); }
get => GetString("PasswordRequiresDigit");
}
/// <summary>
/// Passwords must have at least one digit ('0'-'9').
/// </summary>
internal static string FormatPasswordRequiresDigit()
{
return GetString("PasswordRequiresDigit");
}
=> GetString("PasswordRequiresDigit");
/// <summary>
/// Passwords must have at least one lowercase ('a'-'z').
/// </summary>
internal static string PasswordRequiresLower
{
get { return GetString("PasswordRequiresLower"); }
get => GetString("PasswordRequiresLower");
}
/// <summary>
/// Passwords must have at least one lowercase ('a'-'z').
/// </summary>
internal static string FormatPasswordRequiresLower()
{
return GetString("PasswordRequiresLower");
}
=> GetString("PasswordRequiresLower");
/// <summary>
/// Passwords must have at least one non alphanumeric character.
/// </summary>
internal static string PasswordRequiresNonAlphanumeric
{
get { return GetString("PasswordRequiresNonAlphanumeric"); }
get => GetString("PasswordRequiresNonAlphanumeric");
}
/// <summary>
/// Passwords must have at least one non alphanumeric character.
/// </summary>
internal static string FormatPasswordRequiresNonAlphanumeric()
{
return GetString("PasswordRequiresNonAlphanumeric");
}
=> GetString("PasswordRequiresNonAlphanumeric");
/// <summary>
/// Passwords must have at least one uppercase ('A'-'Z').
/// </summary>
internal static string PasswordRequiresUpper
{
get { return GetString("PasswordRequiresUpper"); }
get => GetString("PasswordRequiresUpper");
}
/// <summary>
/// Passwords must have at least one uppercase ('A'-'Z').
/// </summary>
internal static string FormatPasswordRequiresUpper()
{
return GetString("PasswordRequiresUpper");
}
=> GetString("PasswordRequiresUpper");
/// <summary>
/// Passwords must be at least {0} characters.
/// </summary>
internal static string PasswordTooShort
{
get { return GetString("PasswordTooShort"); }
get => GetString("PasswordTooShort");
}
/// <summary>
/// Passwords must be at least {0} characters.
/// </summary>
internal static string FormatPasswordTooShort(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("PasswordTooShort"), p0);
}
=> string.Format(CultureInfo.CurrentCulture, GetString("PasswordTooShort"), p0);
/// <summary>
/// Role {0} does not exist.
/// </summary>
internal static string RoleNotFound
{
get { return GetString("RoleNotFound"); }
get => GetString("RoleNotFound");
}
/// <summary>
/// Role {0} does not exist.
/// </summary>
internal static string FormatRoleNotFound(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("RoleNotFound"), p0);
}
=> string.Format(CultureInfo.CurrentCulture, GetString("RoleNotFound"), p0);
/// <summary>
/// Store does not implement IQueryableRoleStore&lt;TRole&gt;.
/// </summary>
internal static string StoreNotIQueryableRoleStore
{
get { return GetString("StoreNotIQueryableRoleStore"); }
get => GetString("StoreNotIQueryableRoleStore");
}
/// <summary>
/// Store does not implement IQueryableRoleStore&lt;TRole&gt;.
/// </summary>
internal static string FormatStoreNotIQueryableRoleStore()
{
return GetString("StoreNotIQueryableRoleStore");
}
=> GetString("StoreNotIQueryableRoleStore");
/// <summary>
/// Store does not implement IQueryableUserStore&lt;TUser&gt;.
/// </summary>
internal static string StoreNotIQueryableUserStore
{
get { return GetString("StoreNotIQueryableUserStore"); }
get => GetString("StoreNotIQueryableUserStore");
}
/// <summary>
/// Store does not implement IQueryableUserStore&lt;TUser&gt;.
/// </summary>
internal static string FormatStoreNotIQueryableUserStore()
{
return GetString("StoreNotIQueryableUserStore");
}
=> GetString("StoreNotIQueryableUserStore");
/// <summary>
/// Store does not implement IRoleClaimStore&lt;TRole&gt;.
/// </summary>
internal static string StoreNotIRoleClaimStore
{
get { return GetString("StoreNotIRoleClaimStore"); }
get => GetString("StoreNotIRoleClaimStore");
}
/// <summary>
/// Store does not implement IRoleClaimStore&lt;TRole&gt;.
/// </summary>
internal static string FormatStoreNotIRoleClaimStore()
{
return GetString("StoreNotIRoleClaimStore");
}
=> GetString("StoreNotIRoleClaimStore");
/// <summary>
/// Store does not implement IUserAuthenticationTokenStore&lt;User&gt;.
/// </summary>
internal static string StoreNotIUserAuthenticationTokenStore
{
get { return GetString("StoreNotIUserAuthenticationTokenStore"); }
get => GetString("StoreNotIUserAuthenticationTokenStore");
}
/// <summary>
/// Store does not implement IUserAuthenticationTokenStore&lt;User&gt;.
/// </summary>
internal static string FormatStoreNotIUserAuthenticationTokenStore()
{
return GetString("StoreNotIUserAuthenticationTokenStore");
}
=> GetString("StoreNotIUserAuthenticationTokenStore");
/// <summary>
/// Store does not implement IUserClaimStore&lt;TUser&gt;.
/// </summary>
internal static string StoreNotIUserClaimStore
{
get { return GetString("StoreNotIUserClaimStore"); }
get => GetString("StoreNotIUserClaimStore");
}
/// <summary>
/// Store does not implement IUserClaimStore&lt;TUser&gt;.
/// </summary>
internal static string FormatStoreNotIUserClaimStore()
{
return GetString("StoreNotIUserClaimStore");
}
=> GetString("StoreNotIUserClaimStore");
/// <summary>
/// Store does not implement IUserConfirmationStore&lt;TUser&gt;.
/// </summary>
internal static string StoreNotIUserConfirmationStore
{
get { return GetString("StoreNotIUserConfirmationStore"); }
get => GetString("StoreNotIUserConfirmationStore");
}
/// <summary>
/// Store does not implement IUserConfirmationStore&lt;TUser&gt;.
/// </summary>
internal static string FormatStoreNotIUserConfirmationStore()
{
return GetString("StoreNotIUserConfirmationStore");
}
=> GetString("StoreNotIUserConfirmationStore");
/// <summary>
/// Store does not implement IUserEmailStore&lt;TUser&gt;.
/// </summary>
internal static string StoreNotIUserEmailStore
{
get { return GetString("StoreNotIUserEmailStore"); }
get => GetString("StoreNotIUserEmailStore");
}
/// <summary>
/// Store does not implement IUserEmailStore&lt;TUser&gt;.
/// </summary>
internal static string FormatStoreNotIUserEmailStore()
{
return GetString("StoreNotIUserEmailStore");
}
=> GetString("StoreNotIUserEmailStore");
/// <summary>
/// Store does not implement IUserLockoutStore&lt;TUser&gt;.
/// </summary>
internal static string StoreNotIUserLockoutStore
{
get { return GetString("StoreNotIUserLockoutStore"); }
get => GetString("StoreNotIUserLockoutStore");
}
/// <summary>
/// Store does not implement IUserLockoutStore&lt;TUser&gt;.
/// </summary>
internal static string FormatStoreNotIUserLockoutStore()
{
return GetString("StoreNotIUserLockoutStore");
}
=> GetString("StoreNotIUserLockoutStore");
/// <summary>
/// Store does not implement IUserLoginStore&lt;TUser&gt;.
/// </summary>
internal static string StoreNotIUserLoginStore
{
get { return GetString("StoreNotIUserLoginStore"); }
get => GetString("StoreNotIUserLoginStore");
}
/// <summary>
/// Store does not implement IUserLoginStore&lt;TUser&gt;.
/// </summary>
internal static string FormatStoreNotIUserLoginStore()
{
return GetString("StoreNotIUserLoginStore");
}
=> GetString("StoreNotIUserLoginStore");
/// <summary>
/// Store does not implement IUserPasswordStore&lt;TUser&gt;.
/// </summary>
internal static string StoreNotIUserPasswordStore
{
get { return GetString("StoreNotIUserPasswordStore"); }
get => GetString("StoreNotIUserPasswordStore");
}
/// <summary>
/// Store does not implement IUserPasswordStore&lt;TUser&gt;.
/// </summary>
internal static string FormatStoreNotIUserPasswordStore()
{
return GetString("StoreNotIUserPasswordStore");
}
=> GetString("StoreNotIUserPasswordStore");
/// <summary>
/// Store does not implement IUserPhoneNumberStore&lt;TUser&gt;.
/// </summary>
internal static string StoreNotIUserPhoneNumberStore
{
get { return GetString("StoreNotIUserPhoneNumberStore"); }
get => GetString("StoreNotIUserPhoneNumberStore");
}
/// <summary>
/// Store does not implement IUserPhoneNumberStore&lt;TUser&gt;.
/// </summary>
internal static string FormatStoreNotIUserPhoneNumberStore()
{
return GetString("StoreNotIUserPhoneNumberStore");
}
=> GetString("StoreNotIUserPhoneNumberStore");
/// <summary>
/// Store does not implement IUserRoleStore&lt;TUser&gt;.
/// </summary>
internal static string StoreNotIUserRoleStore
{
get { return GetString("StoreNotIUserRoleStore"); }
get => GetString("StoreNotIUserRoleStore");
}
/// <summary>
/// Store does not implement IUserRoleStore&lt;TUser&gt;.
/// </summary>
internal static string FormatStoreNotIUserRoleStore()
{
return GetString("StoreNotIUserRoleStore");
}
=> GetString("StoreNotIUserRoleStore");
/// <summary>
/// Store does not implement IUserSecurityStampStore&lt;TUser&gt;.
/// </summary>
internal static string StoreNotIUserSecurityStampStore
{
get { return GetString("StoreNotIUserSecurityStampStore"); }
get => GetString("StoreNotIUserSecurityStampStore");
}
/// <summary>
/// Store does not implement IUserSecurityStampStore&lt;TUser&gt;.
/// </summary>
internal static string FormatStoreNotIUserSecurityStampStore()
{
return GetString("StoreNotIUserSecurityStampStore");
}
=> GetString("StoreNotIUserSecurityStampStore");
/// <summary>
/// Store does not implement IUserAuthenticatorKeyStore&lt;User&gt;.
/// </summary>
internal static string StoreNotIUserAuthenticatorKeyStore
{
get { return GetString("StoreNotIUserAuthenticatorKeyStore"); }
get => GetString("StoreNotIUserAuthenticatorKeyStore");
}
/// <summary>
/// Store does not implement IUserAuthenticatorKeyStore&lt;User&gt;.
/// </summary>
internal static string FormatStoreNotIUserAuthenticatorKeyStore()
{
return GetString("StoreNotIUserAuthenticatorKeyStore");
}
=> GetString("StoreNotIUserAuthenticatorKeyStore");
/// <summary>
/// Store does not implement IUserTwoFactorStore&lt;TUser&gt;.
/// </summary>
internal static string StoreNotIUserTwoFactorStore
{
get { return GetString("StoreNotIUserTwoFactorStore"); }
get => GetString("StoreNotIUserTwoFactorStore");
}
/// <summary>
/// Store does not implement IUserTwoFactorStore&lt;TUser&gt;.
/// </summary>
internal static string FormatStoreNotIUserTwoFactorStore()
{
return GetString("StoreNotIUserTwoFactorStore");
}
=> GetString("StoreNotIUserTwoFactorStore");
/// <summary>
/// Recovery code redemption failed.
/// </summary>
internal static string RecoveryCodeRedemptionFailed
{
get { return GetString("RecoveryCodeRedemptionFailed"); }
get => GetString("RecoveryCodeRedemptionFailed");
}
/// <summary>
/// Recovery code redemption failed.
/// </summary>
internal static string FormatRecoveryCodeRedemptionFailed()
{
return GetString("RecoveryCodeRedemptionFailed");
}
=> GetString("RecoveryCodeRedemptionFailed");
/// <summary>
/// User already has a password set.
/// </summary>
internal static string UserAlreadyHasPassword
{
get { return GetString("UserAlreadyHasPassword"); }
get => GetString("UserAlreadyHasPassword");
}
/// <summary>
/// User already has a password set.
/// </summary>
internal static string FormatUserAlreadyHasPassword()
{
return GetString("UserAlreadyHasPassword");
}
=> GetString("UserAlreadyHasPassword");
/// <summary>
/// User already in role '{0}'.
/// </summary>
internal static string UserAlreadyInRole
{
get { return GetString("UserAlreadyInRole"); }
get => GetString("UserAlreadyInRole");
}
/// <summary>
/// User already in role '{0}'.
/// </summary>
internal static string FormatUserAlreadyInRole(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("UserAlreadyInRole"), p0);
}
=> string.Format(CultureInfo.CurrentCulture, GetString("UserAlreadyInRole"), p0);
/// <summary>
/// User is locked out.
/// </summary>
internal static string UserLockedOut
{
get { return GetString("UserLockedOut"); }
get => GetString("UserLockedOut");
}
/// <summary>
/// User is locked out.
/// </summary>
internal static string FormatUserLockedOut()
{
return GetString("UserLockedOut");
}
=> GetString("UserLockedOut");
/// <summary>
/// Lockout is not enabled for this user.
/// </summary>
internal static string UserLockoutNotEnabled
{
get { return GetString("UserLockoutNotEnabled"); }
get => GetString("UserLockoutNotEnabled");
}
/// <summary>
/// Lockout is not enabled for this user.
/// </summary>
internal static string FormatUserLockoutNotEnabled()
{
return GetString("UserLockoutNotEnabled");
}
=> GetString("UserLockoutNotEnabled");
/// <summary>
/// User {0} does not exist.
/// </summary>
internal static string UserNameNotFound
{
get { return GetString("UserNameNotFound"); }
get => GetString("UserNameNotFound");
}
/// <summary>
/// User {0} does not exist.
/// </summary>
internal static string FormatUserNameNotFound(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("UserNameNotFound"), p0);
}
=> string.Format(CultureInfo.CurrentCulture, GetString("UserNameNotFound"), p0);
/// <summary>
/// User is not in role '{0}'.
/// </summary>
internal static string UserNotInRole
{
get { return GetString("UserNotInRole"); }
get => GetString("UserNotInRole");
}
/// <summary>
/// User is not in role '{0}'.
/// </summary>
internal static string FormatUserNotInRole(object p0)
{
return string.Format(CultureInfo.CurrentCulture, GetString("UserNotInRole"), p0);
}
=> string.Format(CultureInfo.CurrentCulture, GetString("UserNotInRole"), p0);
/// <summary>
/// Store does not implement IUserTwoFactorRecoveryCodeStore&lt;User&gt;.
/// </summary>
internal static string StoreNotIUserTwoFactorRecoveryCodeStore
{
get { return GetString("StoreNotIUserTwoFactorRecoveryCodeStore"); }
get => GetString("StoreNotIUserTwoFactorRecoveryCodeStore");
}
/// <summary>
/// Store does not implement IUserTwoFactorRecoveryCodeStore&lt;User&gt;.
/// </summary>
internal static string FormatStoreNotIUserTwoFactorRecoveryCodeStore()
{
return GetString("StoreNotIUserTwoFactorRecoveryCodeStore");
}
=> GetString("StoreNotIUserTwoFactorRecoveryCodeStore");
/// <summary>
/// Passwords must use at least {0} different characters.
/// </summary>
internal static string PasswordRequiresUniqueChars
{
get { return GetString("PasswordRequiresUniqueChars"); }
get => GetString("PasswordRequiresUniqueChars");
}
/// <summary>
/// Passwords must use at least {0} different characters.
/// </summary>
internal static string FormatPasswordRequiresUniqueChars(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("PasswordRequiresUniqueChars"), p0);
/// <summary>
/// No RoleType was specified, try AddRoles&lt;TRole&gt;().
/// </summary>
internal static string NoRoleType
{
return string.Format(CultureInfo.CurrentCulture, GetString("PasswordRequiresUniqueChars"), p0);
get => GetString("NoRoleType");
}
/// <summary>
/// No RoleType was specified, try AddRoles&lt;TRole&gt;().
/// </summary>
internal static string FormatNoRoleType()
=> GetString("NoRoleType");
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);

View File

@ -305,4 +305,8 @@
<value>Passwords must use at least {0} different characters.</value>
<comment>Error message for passwords that are based on similar characters</comment>
</data>
<data name="NoRoleType" xml:space="preserve">
<value>No RoleType was specified, try AddRoles&lt;TRole&gt;().</value>
<comment>Error when the IdentityBuilder.RoleType was not specified</comment>
</data>
</root>

View File

@ -7,6 +7,7 @@ using System.Linq;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Identity.Core;
using Microsoft.Extensions.Logging;
namespace Microsoft.AspNetCore.Identity

View File

@ -13,36 +13,27 @@ namespace Microsoft.AspNetCore.Identity
/// Provides methods to create a claims principal for a given user.
/// </summary>
/// <typeparam name="TUser">The type used to represent a user.</typeparam>
/// <typeparam name="TRole">The type used to represent a role.</typeparam>
public class UserClaimsPrincipalFactory<TUser, TRole> : IUserClaimsPrincipalFactory<TUser>
public class UserClaimsPrincipalFactory<TUser> : IUserClaimsPrincipalFactory<TUser>
where TUser : class
where TRole : class
{
/// <summary>
/// Initializes a new instance of the <see cref="UserClaimsPrincipalFactory{TUser, TRole}"/> class.
/// Initializes a new instance of the <see cref="UserClaimsPrincipalFactory{TUser}"/> class.
/// </summary>
/// <param name="userManager">The <see cref="UserManager{TUser}"/> to retrieve user information from.</param>
/// <param name="roleManager">The <see cref="RoleManager{TRole}"/> to retrieve a user's roles from.</param>
/// <param name="optionsAccessor">The configured <see cref="IdentityOptions"/>.</param>
public UserClaimsPrincipalFactory(
UserManager<TUser> userManager,
RoleManager<TRole> roleManager,
UserManager<TUser> userManager,
IOptions<IdentityOptions> optionsAccessor)
{
if (userManager == null)
{
throw new ArgumentNullException(nameof(userManager));
}
if (roleManager == null)
{
throw new ArgumentNullException(nameof(roleManager));
}
if (optionsAccessor == null || optionsAccessor.Value == null)
{
throw new ArgumentNullException(nameof(optionsAccessor));
}
UserManager = userManager;
RoleManager = roleManager;
Options = optionsAccessor.Value;
}
@ -54,14 +45,6 @@ namespace Microsoft.AspNetCore.Identity
/// </value>
public UserManager<TUser> UserManager { get; private set; }
/// <summary>
/// Gets the <see cref="RoleManager{TRole}"/> for this factory.
/// </summary>
/// <value>
/// The current <see cref="RoleManager{TRole}"/> for this factory instance.
/// </value>
public RoleManager<TRole> RoleManager { get; private set; }
/// <summary>
/// Gets the <see cref="IdentityOptions"/> for this factory.
/// </summary>
@ -81,18 +64,78 @@ namespace Microsoft.AspNetCore.Identity
{
throw new ArgumentNullException(nameof(user));
}
var id = await GenerateClaimsAsync(user);
return new ClaimsPrincipal(id);
}
/// <summary>
/// Generate the claims for a user.
/// </summary>
/// <param name="user">The user to create a <see cref="ClaimsIdentity"/> from.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous creation operation, containing the created <see cref="ClaimsIdentity"/>.</returns>
protected virtual async Task<ClaimsIdentity> GenerateClaimsAsync(TUser user)
{
var userId = await UserManager.GetUserIdAsync(user);
var userName = await UserManager.GetUserNameAsync(user);
var id = new ClaimsIdentity(IdentityConstants.ApplicationScheme,
var id = new ClaimsIdentity("Identity.Application", // REVIEW: Used to match Application scheme
Options.ClaimsIdentity.UserNameClaimType,
Options.ClaimsIdentity.RoleClaimType);
id.AddClaim(new Claim(Options.ClaimsIdentity.UserIdClaimType, userId));
id.AddClaim(new Claim(Options.ClaimsIdentity.UserNameClaimType, userName));
if (UserManager.SupportsUserSecurityStamp)
{
id.AddClaim(new Claim(Options.ClaimsIdentity.SecurityStampClaimType,
id.AddClaim(new Claim(Options.ClaimsIdentity.SecurityStampClaimType,
await UserManager.GetSecurityStampAsync(user)));
}
if (UserManager.SupportsUserClaim)
{
id.AddClaims(await UserManager.GetClaimsAsync(user));
}
return id;
}
}
/// <summary>
/// Provides methods to create a claims principal for a given user.
/// </summary>
/// <typeparam name="TUser">The type used to represent a user.</typeparam>
/// <typeparam name="TRole">The type used to represent a role.</typeparam>
public class UserClaimsPrincipalFactory<TUser, TRole> : UserClaimsPrincipalFactory<TUser>
where TUser : class
where TRole : class
{
/// <summary>
/// Initializes a new instance of the <see cref="UserClaimsPrincipalFactory{TUser, TRole}"/> class.
/// </summary>
/// <param name="userManager">The <see cref="UserManager{TUser}"/> to retrieve user information from.</param>
/// <param name="roleManager">The <see cref="RoleManager{TRole}"/> to retrieve a user's roles from.</param>
/// <param name="options">The configured <see cref="IdentityOptions"/>.</param>
public UserClaimsPrincipalFactory(UserManager<TUser> userManager, RoleManager<TRole> roleManager, IOptions<IdentityOptions> options)
: base(userManager, options)
{
if (roleManager == null)
{
throw new ArgumentNullException(nameof(roleManager));
}
RoleManager = roleManager;
}
/// <summary>
/// Gets the <see cref="RoleManager{TRole}"/> for this factory.
/// </summary>
/// <value>
/// The current <see cref="RoleManager{TRole}"/> for this factory instance.
/// </value>
public RoleManager<TRole> RoleManager { get; private set; }
/// <summary>
/// Generate the claims for a user.
/// </summary>
/// <param name="user">The user to create a <see cref="ClaimsIdentity"/> from.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous creation operation, containing the created <see cref="ClaimsIdentity"/>.</returns>
protected override async Task<ClaimsIdentity> GenerateClaimsAsync(TUser user)
{
var id = await base.GenerateClaimsAsync(user);
if (UserManager.SupportsUserRole)
{
var roles = await UserManager.GetRolesAsync(user);
@ -109,21 +152,7 @@ namespace Microsoft.AspNetCore.Identity
}
}
}
if (UserManager.SupportsUserClaim)
{
id.AddClaims(await UserManager.GetClaimsAsync(user));
}
return await CreatePrincipalAsync(id);
}
/// <summary>
/// Creates a <see cref="ClaimsPrincipal"/> from a <see cref="ClaimsIdentity"/>.
/// </summary>
/// <param name="id">The <see cref="ClaimsIdentity"/> with claims.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous creation operation, containing the <see cref="ClaimsPrincipal"/> with the <see cref="ClaimsIdentity"/>.</returns>
protected virtual Task<ClaimsPrincipal> CreatePrincipalAsync(ClaimsIdentity id)
{
return Task.FromResult(new ClaimsPrincipal(id));
return id;
}
}
}

View File

@ -12,6 +12,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Identity.Core;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
namespace Microsoft.AspNetCore.Identity
{
@ -39,34 +38,7 @@ namespace Microsoft.AspNetCore.Identity
/// Represents a role in the identity system
/// </summary>
/// <typeparam name="TKey">The type used for the primary key for the role.</typeparam>
public class IdentityRole<TKey> : IdentityRole<TKey, IdentityUserRole<TKey>, IdentityRoleClaim<TKey>>
where TKey : IEquatable<TKey>
{
/// <summary>
/// Initializes a new instance of <see cref="IdentityRole{TKey}"/>.
/// </summary>
public IdentityRole() { }
/// <summary>
/// Initializes a new instance of <see cref="IdentityRole{TKey}"/>.
/// </summary>
/// <param name="roleName">The role name.</param>
public IdentityRole(string roleName) : this()
{
Name = roleName;
}
}
/// <summary>
/// Represents a role in the identity system
/// </summary>
/// <typeparam name="TKey">The type used for the primary key for the role.</typeparam>
/// <typeparam name="TUserRole">The type used for user roles.</typeparam>
/// <typeparam name="TRoleClaim">The type used for role claims.</typeparam>
public class IdentityRole<TKey, TUserRole, TRoleClaim>
where TKey : IEquatable<TKey>
where TUserRole : IdentityUserRole<TKey>
where TRoleClaim : IdentityRoleClaim<TKey>
public class IdentityRole<TKey> where TKey : IEquatable<TKey>
{
/// <summary>
/// Initializes a new instance of <see cref="IdentityRole{TKey}"/>.

View File

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
namespace Microsoft.AspNetCore.Identity
{
@ -39,19 +38,7 @@ namespace Microsoft.AspNetCore.Identity
/// Represents a user in the identity system
/// </summary>
/// <typeparam name="TKey">The type used for the primary key for the user.</typeparam>
public class IdentityUser<TKey> : IdentityUser<TKey, IdentityUserClaim<TKey>, IdentityUserRole<TKey>, IdentityUserLogin<TKey>, IdentityUserToken<TKey>>
where TKey : IEquatable<TKey>
{ }
/// <summary>
/// Represents a user in the identity system
/// </summary>
/// <typeparam name="TKey">The type used for the primary key for the user.</typeparam>
/// <typeparam name="TUserClaim">The type representing a claim.</typeparam>
/// <typeparam name="TUserRole">The type representing a user role.</typeparam>
/// <typeparam name="TUserLogin">The type representing a user external login.</typeparam>
/// <typeparam name="TUserToken">The type representing a user external login.</typeparam>
public class IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin, TUserToken> where TKey : IEquatable<TKey>
public class IdentityUser<TKey> where TKey : IEquatable<TKey>
{
/// <summary>
/// Initializes a new instance of <see cref="IdentityUser{TKey}"/>.

View File

@ -22,7 +22,7 @@ namespace Microsoft.AspNetCore.Identity
public abstract class RoleStoreBase<TRole, TKey, TUserRole, TRoleClaim> :
IQueryableRoleStore<TRole>,
IRoleClaimStore<TRole>
where TRole : IdentityRole<TKey, TUserRole, TRoleClaim>
where TRole : IdentityRole<TKey>
where TKey : IEquatable<TKey>
where TUserRole : IdentityUserRole<TKey>, new()
where TRoleClaim : IdentityRoleClaim<TKey>, new()
@ -219,10 +219,7 @@ namespace Microsoft.AspNetCore.Identity
/// <summary>
/// Dispose the stores
/// </summary>
public void Dispose()
{
_disposed = true;
}
public void Dispose() => _disposed = true;
/// <summary>
/// Get the claims associated with the specified <paramref name="role"/> as an asynchronous operation.
@ -265,8 +262,6 @@ namespace Microsoft.AspNetCore.Identity
/// <param name="claim">The associated claim.</param>
/// <returns>The role claim entity.</returns>
protected virtual TRoleClaim CreateRoleClaim(TRole role, Claim claim)
{
return new TRoleClaim { RoleId = role.Id, ClaimType = claim.Type, ClaimValue = claim.Value };
}
=> new TRoleClaim { RoleId = role.Id, ClaimType = claim.Type, ClaimValue = claim.Value };
}
}

View File

@ -8,24 +8,19 @@ using System.Linq;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Identity
{
/// <summary>
/// Represents a new instance of a persistence store for the specified user and role types.
/// Represents a new instance of a persistence store for the specified user type.
/// </summary>
/// <typeparam name="TUser">The type representing a user.</typeparam>
/// <typeparam name="TRole">The type representing a role.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a role.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a user.</typeparam>
/// <typeparam name="TUserClaim">The type representing a claim.</typeparam>
/// <typeparam name="TUserRole">The type representing a user role.</typeparam>
/// <typeparam name="TUserLogin">The type representing a user external login.</typeparam>
/// <typeparam name="TUserToken">The type representing a user token.</typeparam>
/// <typeparam name="TRoleClaim">The type representing a role claim.</typeparam>
public abstract class UserStoreBase<TUser, TRole, TKey, TUserClaim, TUserRole, TUserLogin, TUserToken, TRoleClaim> :
public abstract class UserStoreBase<TUser, TKey, TUserClaim, TUserLogin, TUserToken> :
IUserLoginStore<TUser>,
IUserRoleStore<TUser>,
IUserClaimStore<TUser>,
IUserPasswordStore<TUser>,
IUserSecurityStampStore<TUser>,
@ -37,14 +32,11 @@ namespace Microsoft.AspNetCore.Identity
IUserAuthenticationTokenStore<TUser>,
IUserAuthenticatorKeyStore<TUser>,
IUserTwoFactorRecoveryCodeStore<TUser>
where TUser : IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin, TUserToken>
where TRole : IdentityRole<TKey, TUserRole, TRoleClaim>
where TUser : IdentityUser<TKey>
where TKey : IEquatable<TKey>
where TUserClaim : IdentityUserClaim<TKey>, new()
where TUserRole : IdentityUserRole<TKey>, new()
where TUserLogin : IdentityUserLogin<TKey>, new()
where TUserToken : IdentityUserToken<TKey>, new()
where TRoleClaim : IdentityRoleClaim<TKey>, new()
{
/// <summary>
/// Creates a new instance.
@ -67,21 +59,6 @@ namespace Microsoft.AspNetCore.Identity
/// </summary>
public IdentityErrorDescriber ErrorDescriber { get; set; }
/// <summary>
/// Called to create a new instance of a <see cref="IdentityUserRole{TKey}"/>.
/// </summary>
/// <param name="user">The associated user.</param>
/// <param name="role">The associated role.</param>
/// <returns></returns>
protected virtual TUserRole CreateUserRole(TUser user, TRole role)
{
return new TUserRole()
{
UserId = user.Id,
RoleId = role.Id
};
}
/// <summary>
/// Called to create a new instance of a <see cref="IdentityUserClaim{TKey}"/>.
/// </summary>
@ -349,23 +326,6 @@ namespace Microsoft.AspNetCore.Identity
return Task.FromResult(user.PasswordHash != null);
}
/// <summary>
/// Return a role with the normalized name if it exists.
/// </summary>
/// <param name="normalizedRoleName">The normalized role name.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The role if it exists.</returns>
protected abstract Task<TRole> FindRoleAsync(string normalizedRoleName, CancellationToken cancellationToken);
/// <summary>
/// Return a user role for the userId and roleId if it exists.
/// </summary>
/// <param name="userId">The user's id.</param>
/// <param name="roleId">The role's id.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The user role if it exists.</returns>
protected abstract Task<TUserRole> FindUserRoleAsync(TKey userId, TKey roleId, CancellationToken cancellationToken);
/// <summary>
/// Return a user with the matching userId if it exists.
/// </summary>
@ -393,42 +353,6 @@ namespace Microsoft.AspNetCore.Identity
/// <returns>The user login if it exists.</returns>
protected abstract Task<TUserLogin> FindUserLoginAsync(string loginProvider, string providerKey, CancellationToken cancellationToken);
/// <summary>
/// Adds the given <paramref name="normalizedRoleName"/> to the specified <paramref name="user"/>.
/// </summary>
/// <param name="user">The user to add the role to.</param>
/// <param name="normalizedRoleName">The role to add.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
public abstract Task AddToRoleAsync(TUser user, string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Removes the given <paramref name="normalizedRoleName"/> from the specified <paramref name="user"/>.
/// </summary>
/// <param name="user">The user to remove the role from.</param>
/// <param name="normalizedRoleName">The role to remove.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
public abstract Task RemoveFromRoleAsync(TUser user, string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Retrieves the roles the specified <paramref name="user"/> is a member of.
/// </summary>
/// <param name="user">The user whose roles should be retrieved.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>A <see cref="Task{TResult}"/> that contains the roles the user is a member of.</returns>
public abstract Task<IList<string>> GetRolesAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Returns a flag indicating if the specified user is a member of the give <paramref name="normalizedRoleName"/>.
/// </summary>
/// <param name="user">The user whose role membership should be checked.</param>
/// <param name="normalizedRoleName">The role to check membership of</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>A <see cref="Task{TResult}"/> containing a flag indicating if the specified user is a member of the given group. If the
/// user is a member of the group the returned value with be true, otherwise it will be false.</returns>
public abstract Task<bool> IsInRoleAsync(TUser user, string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Throws if this class has been disposed.
/// </summary>
@ -957,16 +881,6 @@ namespace Microsoft.AspNetCore.Identity
/// </returns>
public abstract Task<IList<TUser>> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Retrieves all users in the specified role.
/// </summary>
/// <param name="normalizedRoleName">The role whose users should be retrieved.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>
/// The <see cref="Task"/> contains a list of users, if any, that are in the specified role.
/// </returns>
public abstract Task<IList<TUser>> GetUsersInRoleAsync(string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Find a user token if it exists.
/// </summary>
@ -1139,4 +1053,113 @@ namespace Microsoft.AspNetCore.Identity
return false;
}
}
/// <summary>
/// Represents a new instance of a persistence store for the specified user and role types.
/// </summary>
/// <typeparam name="TUser">The type representing a user.</typeparam>
/// <typeparam name="TRole">The type representing a role.</typeparam>
/// <typeparam name="TKey">The type of the primary key for a role.</typeparam>
/// <typeparam name="TUserClaim">The type representing a claim.</typeparam>
/// <typeparam name="TUserRole">The type representing a user role.</typeparam>
/// <typeparam name="TUserLogin">The type representing a user external login.</typeparam>
/// <typeparam name="TUserToken">The type representing a user token.</typeparam>
/// <typeparam name="TRoleClaim">The type representing a role claim.</typeparam>
public abstract class UserStoreBase<TUser, TRole, TKey, TUserClaim, TUserRole, TUserLogin, TUserToken, TRoleClaim> :
UserStoreBase<TUser, TKey, TUserClaim, TUserLogin, TUserToken>,
IUserRoleStore<TUser>
where TUser : IdentityUser<TKey>
where TRole : IdentityRole<TKey>
where TKey : IEquatable<TKey>
where TUserClaim : IdentityUserClaim<TKey>, new()
where TUserRole : IdentityUserRole<TKey>, new()
where TUserLogin : IdentityUserLogin<TKey>, new()
where TUserToken : IdentityUserToken<TKey>, new()
where TRoleClaim : IdentityRoleClaim<TKey>, new()
{
/// <summary>
/// Creates a new instance.
/// </summary>
/// <param name="describer">The <see cref="IdentityErrorDescriber"/> used to describe store errors.</param>
public UserStoreBase(IdentityErrorDescriber describer) : base(describer) { }
/// <summary>
/// Called to create a new instance of a <see cref="IdentityUserRole{TKey}"/>.
/// </summary>
/// <param name="user">The associated user.</param>
/// <param name="role">The associated role.</param>
/// <returns></returns>
protected virtual TUserRole CreateUserRole(TUser user, TRole role)
{
return new TUserRole()
{
UserId = user.Id,
RoleId = role.Id
};
}
/// <summary>
/// Retrieves all users in the specified role.
/// </summary>
/// <param name="normalizedRoleName">The role whose users should be retrieved.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>
/// The <see cref="Task"/> contains a list of users, if any, that are in the specified role.
/// </returns>
public abstract Task<IList<TUser>> GetUsersInRoleAsync(string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Adds the given <paramref name="normalizedRoleName"/> to the specified <paramref name="user"/>.
/// </summary>
/// <param name="user">The user to add the role to.</param>
/// <param name="normalizedRoleName">The role to add.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
public abstract Task AddToRoleAsync(TUser user, string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Removes the given <paramref name="normalizedRoleName"/> from the specified <paramref name="user"/>.
/// </summary>
/// <param name="user">The user to remove the role from.</param>
/// <param name="normalizedRoleName">The role to remove.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="Task"/> that represents the asynchronous operation.</returns>
public abstract Task RemoveFromRoleAsync(TUser user, string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Retrieves the roles the specified <paramref name="user"/> is a member of.
/// </summary>
/// <param name="user">The user whose roles should be retrieved.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>A <see cref="Task{TResult}"/> that contains the roles the user is a member of.</returns>
public abstract Task<IList<string>> GetRolesAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Returns a flag indicating if the specified user is a member of the give <paramref name="normalizedRoleName"/>.
/// </summary>
/// <param name="user">The user whose role membership should be checked.</param>
/// <param name="normalizedRoleName">The role to check membership of</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>A <see cref="Task{TResult}"/> containing a flag indicating if the specified user is a member of the given group. If the
/// user is a member of the group the returned value with be true, otherwise it will be false.</returns>
public abstract Task<bool> IsInRoleAsync(TUser user, string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken));
/// <summary>
/// Return a role with the normalized name if it exists.
/// </summary>
/// <param name="normalizedRoleName">The normalized role name.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The role if it exists.</returns>
protected abstract Task<TRole> FindRoleAsync(string normalizedRoleName, CancellationToken cancellationToken);
/// <summary>
/// Return a user role for the userId and roleId if it exists.
/// </summary>
/// <param name="userId">The user's id.</param>
/// <param name="roleId">The role's id.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The user role if it exists.</returns>
protected abstract Task<TUserRole> FindUserRoleAsync(TKey userId, TKey roleId, CancellationToken cancellationToken);
}
}

View File

@ -14,11 +14,16 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test
}
public class InMemoryContext<TUser> :
InMemoryContext<TUser, IdentityRole, string>
IdentityDbContext<TUser, string>
where TUser : IdentityUser
{
public InMemoryContext(DbContextOptions options) : base(options)
{ }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseInMemoryDatabase("ScratchUsers");
}
}
public class InMemoryContext<TUser, TRole, TKey> : IdentityDbContext<TUser, TRole, TKey>
@ -36,8 +41,8 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test
}
public abstract class InMemoryContext<TUser, TRole, TKey, TUserClaim, TUserRole, TUserLogin, TRoleClaim, TUserToken> : IdentityDbContext<TUser, TRole, TKey, TUserClaim, TUserRole, TUserLogin, TRoleClaim, TUserToken>
where TUser : IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin, TUserToken>
where TRole : IdentityRole<TKey, TUserRole, TRoleClaim>
where TUser : IdentityUser<TKey>
where TRole : IdentityRole<TKey>
where TKey : IEquatable<TKey>
where TUserClaim : IdentityUserClaim<TKey>
where TUserRole : IdentityUserRole<TKey>
@ -45,12 +50,9 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test
where TRoleClaim : IdentityRoleClaim<TKey>
where TUserToken : IdentityUserToken<TKey>
{
public InMemoryContext(DbContextOptions options) : base(options)
{ }
public InMemoryContext(DbContextOptions options) : base(options) { }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseInMemoryDatabase("Scratch");
}
=> optionsBuilder.UseInMemoryDatabase("Scratch");
}
}

View File

@ -0,0 +1,42 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq.Expressions;
using Microsoft.AspNetCore.Identity.Test;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test
{
public class InMemoryEFOnlyUsersTest : UserManagerSpecificationTestBase<IdentityUser, string>
{
protected override object CreateTestContext()
=> new InMemoryContext<IdentityUser>(new DbContextOptionsBuilder().Options);
protected override void AddUserStore(IServiceCollection services, object context = null)
=> services.AddSingleton<IUserStore<IdentityUser>>(new UserStore<IdentityUser, IdentityRole, DbContext, string, IdentityUserClaim<string>, IdentityUserRole<string>, IdentityUserLogin<string>, IdentityUserToken<string>, IdentityRoleClaim<string>>((InMemoryContext<IdentityUser>)context, new IdentityErrorDescriber()));
protected override IdentityUser CreateTestUser(string namePrefix = "", string email = "", string phoneNumber = "",
bool lockoutEnabled = false, DateTimeOffset? lockoutEnd = default(DateTimeOffset?), bool useNamePrefixAsUserName = false)
{
return new IdentityUser
{
UserName = useNamePrefixAsUserName ? namePrefix : string.Format("{0}{1}", namePrefix, Guid.NewGuid()),
Email = email,
PhoneNumber = phoneNumber,
LockoutEnabled = lockoutEnabled,
LockoutEnd = lockoutEnd
};
}
protected override void SetUserPasswordHash(IdentityUser user, string hashedPassword)
{
user.PasswordHash = hashedPassword;
}
protected override Expression<Func<IdentityUser, bool>> UserNameEqualsPredicate(string userName) => u => u.UserName == userName;
protected override Expression<Func<IdentityUser, bool>> UserNameStartsWithPredicate(string userName) => u => u.UserName.StartsWith(userName);
}
}

View File

@ -188,7 +188,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test
#region Generic Type defintions
public class IdentityUserWithGenerics : IdentityUser<string, IdentityUserClaimWithIssuer, IdentityUserRoleWithDate, IdentityUserLoginWithContext, IdentityUserTokenWithStuff>
public class IdentityUserWithGenerics : IdentityUser<string>
{
public IdentityUserWithGenerics()
{
@ -294,7 +294,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test
public DateTime Created { get; set; }
}
public class MyIdentityRole : IdentityRole<string, IdentityUserRoleWithDate, IdentityRoleClaimWithIssuer>
public class MyIdentityRole : IdentityRole<string>
{
public MyIdentityRole() : base()
{

View File

@ -0,0 +1,290 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Data.SqlClient;
using System.Linq;
using System.Linq.Expressions;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity.Test;
using Microsoft.AspNetCore.Testing;
using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test
{
public abstract class SqlStoreOnlyUsersTestBase<TUser, TKey> : UserManagerSpecificationTestBase<TUser, TKey>, IClassFixture<ScratchDatabaseFixture>
where TUser : IdentityUser<TKey>, new()
where TKey : IEquatable<TKey>
{
private readonly ScratchDatabaseFixture _fixture;
protected SqlStoreOnlyUsersTestBase(ScratchDatabaseFixture fixture)
{
_fixture = fixture;
}
protected override bool ShouldSkipDbTests()
{
return TestPlatformHelper.IsMono || !TestPlatformHelper.IsWindows;
}
public class TestUserDbContext : IdentityDbContext<TUser, TKey>
{
public TestUserDbContext(DbContextOptions options) : base(options) { }
}
protected override TUser CreateTestUser(string namePrefix = "", string email = "", string phoneNumber = "",
bool lockoutEnabled = false, DateTimeOffset? lockoutEnd = default(DateTimeOffset?), bool useNamePrefixAsUserName = false)
{
return new TUser
{
UserName = useNamePrefixAsUserName ? namePrefix : string.Format("{0}{1}", namePrefix, Guid.NewGuid()),
Email = email,
PhoneNumber = phoneNumber,
LockoutEnabled = lockoutEnabled,
LockoutEnd = lockoutEnd
};
}
protected override Expression<Func<TUser, bool>> UserNameEqualsPredicate(string userName) => u => u.UserName == userName;
protected override Expression<Func<TUser, bool>> UserNameStartsWithPredicate(string userName) => u => u.UserName.StartsWith(userName);
public TestUserDbContext CreateContext()
{
var db = DbUtil.Create<TestUserDbContext>(_fixture.ConnectionString);
db.Database.EnsureCreated();
return db;
}
protected override object CreateTestContext()
{
return CreateContext();
}
protected override void AddUserStore(IServiceCollection services, object context = null)
{
services.AddSingleton<IUserStore<TUser>>(new UserOnlyStore<TUser, TestUserDbContext, TKey>((TestUserDbContext)context));
}
protected override void SetUserPasswordHash(TUser user, string hashedPassword)
{
user.PasswordHash = hashedPassword;
}
[ConditionalFact]
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
[OSSkipCondition(OperatingSystems.Linux)]
[OSSkipCondition(OperatingSystems.MacOSX)]
public void EnsureDefaultSchema()
{
VerifyDefaultSchema(CreateContext());
}
internal static void VerifyDefaultSchema(TestUserDbContext dbContext)
{
var sqlConn = dbContext.Database.GetDbConnection();
using (var db = new SqlConnection(sqlConn.ConnectionString))
{
db.Open();
Assert.True(VerifyColumns(db, "AspNetUsers", "Id", "UserName", "Email", "PasswordHash", "SecurityStamp",
"EmailConfirmed", "PhoneNumber", "PhoneNumberConfirmed", "TwoFactorEnabled", "LockoutEnabled",
"LockoutEnd", "AccessFailedCount", "ConcurrencyStamp", "NormalizedUserName", "NormalizedEmail"));
Assert.False(VerifyColumns(db, "AspNetRoles", "Id", "Name", "NormalizedName", "ConcurrencyStamp"));
Assert.False(VerifyColumns(db, "AspNetUserRoles", "UserId", "RoleId"));
Assert.True(VerifyColumns(db, "AspNetUserClaims", "Id", "UserId", "ClaimType", "ClaimValue"));
Assert.True(VerifyColumns(db, "AspNetUserLogins", "UserId", "ProviderKey", "LoginProvider", "ProviderDisplayName"));
Assert.True(VerifyColumns(db, "AspNetUserTokens", "UserId", "LoginProvider", "Name", "Value"));
VerifyIndex(db, "AspNetUsers", "UserNameIndex", isUnique: true);
VerifyIndex(db, "AspNetUsers", "EmailIndex");
db.Close();
}
}
internal static bool VerifyColumns(SqlConnection conn, string table, params string[] columns)
{
var count = 0;
using (
var command =
new SqlCommand("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS where TABLE_NAME=@Table", conn))
{
command.Parameters.Add(new SqlParameter("Table", table));
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
count++;
if (!columns.Contains(reader.GetString(0)))
{
return false;
}
}
return count == columns.Length;
}
}
}
internal static void VerifyIndex(SqlConnection conn, string table, string index, bool isUnique = false)
{
using (
var command =
new SqlCommand(
"SELECT COUNT(*) FROM sys.indexes where NAME=@Index AND object_id = OBJECT_ID(@Table) AND is_unique = @Unique", conn))
{
command.Parameters.Add(new SqlParameter("Index", index));
command.Parameters.Add(new SqlParameter("Table", table));
command.Parameters.Add(new SqlParameter("Unique", isUnique));
using (var reader = command.ExecuteReader())
{
Assert.True(reader.Read());
Assert.True(reader.GetInt32(0) > 0);
}
}
}
[ConditionalFact]
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
[OSSkipCondition(OperatingSystems.Linux)]
[OSSkipCondition(OperatingSystems.MacOSX)]
public async Task DeleteUserRemovesTokensTest()
{
// Need fail if not empty?
var userMgr = CreateManager();
var user = CreateTestUser();
IdentityResultAssert.IsSuccess(await userMgr.CreateAsync(user));
IdentityResultAssert.IsSuccess(await userMgr.SetAuthenticationTokenAsync(user, "provider", "test", "value"));
Assert.Equal("value", await userMgr.GetAuthenticationTokenAsync(user, "provider", "test"));
IdentityResultAssert.IsSuccess(await userMgr.DeleteAsync(user));
Assert.Null(await userMgr.GetAuthenticationTokenAsync(user, "provider", "test"));
}
[ConditionalFact]
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
[OSSkipCondition(OperatingSystems.Linux)]
[OSSkipCondition(OperatingSystems.MacOSX)]
public void CanCreateUserUsingEF()
{
using (var db = CreateContext())
{
var user = CreateTestUser();
db.Users.Add(user);
db.SaveChanges();
Assert.True(db.Users.Any(u => u.UserName == user.UserName));
Assert.NotNull(db.Users.FirstOrDefault(u => u.UserName == user.UserName));
}
}
[ConditionalFact]
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
[OSSkipCondition(OperatingSystems.Linux)]
[OSSkipCondition(OperatingSystems.MacOSX)]
public async Task CanCreateUsingManager()
{
var manager = CreateManager();
var user = CreateTestUser();
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
IdentityResultAssert.IsSuccess(await manager.DeleteAsync(user));
}
private async Task LazyLoadTestSetup(TestUserDbContext db, TUser user)
{
var context = CreateContext();
var manager = CreateManager(context);
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
IdentityResultAssert.IsSuccess(await manager.AddLoginAsync(user, new UserLoginInfo("provider", user.Id.ToString(), "display")));
Claim[] userClaims =
{
new Claim("Whatever", "Value"),
new Claim("Whatever2", "Value2")
};
foreach (var c in userClaims)
{
IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user, c));
}
}
[ConditionalFact]
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
[OSSkipCondition(OperatingSystems.Linux)]
[OSSkipCondition(OperatingSystems.MacOSX)]
public async Task LoadFromDbFindByIdTest()
{
var db = CreateContext();
var user = CreateTestUser();
await LazyLoadTestSetup(db, user);
db = CreateContext();
var manager = CreateManager(db);
var userById = await manager.FindByIdAsync(user.Id.ToString());
Assert.Equal(2, (await manager.GetClaimsAsync(userById)).Count);
Assert.Equal(1, (await manager.GetLoginsAsync(userById)).Count);
Assert.Equal(2, (await manager.GetRolesAsync(userById)).Count);
}
[ConditionalFact]
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
[OSSkipCondition(OperatingSystems.Linux)]
[OSSkipCondition(OperatingSystems.MacOSX)]
public async Task LoadFromDbFindByNameTest()
{
var db = CreateContext();
var user = CreateTestUser();
await LazyLoadTestSetup(db, user);
db = CreateContext();
var manager = CreateManager(db);
var userByName = await manager.FindByNameAsync(user.UserName);
Assert.Equal(2, (await manager.GetClaimsAsync(userByName)).Count);
Assert.Equal(1, (await manager.GetLoginsAsync(userByName)).Count);
Assert.Equal(2, (await manager.GetRolesAsync(userByName)).Count);
}
[ConditionalFact]
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
[OSSkipCondition(OperatingSystems.Linux)]
[OSSkipCondition(OperatingSystems.MacOSX)]
public async Task LoadFromDbFindByLoginTest()
{
var db = CreateContext();
var user = CreateTestUser();
await LazyLoadTestSetup(db, user);
db = CreateContext();
var manager = CreateManager(db);
var userByLogin = await manager.FindByLoginAsync("provider", user.Id.ToString());
Assert.Equal(2, (await manager.GetClaimsAsync(userByLogin)).Count);
Assert.Equal(1, (await manager.GetLoginsAsync(userByLogin)).Count);
Assert.Equal(2, (await manager.GetRolesAsync(userByLogin)).Count);
}
[ConditionalFact]
[FrameworkSkipCondition(RuntimeFrameworks.Mono)]
[OSSkipCondition(OperatingSystems.Linux)]
[OSSkipCondition(OperatingSystems.MacOSX)]
public async Task LoadFromDbFindByEmailTest()
{
var db = CreateContext();
var user = CreateTestUser();
user.Email = "fooz@fizzy.pop";
await LazyLoadTestSetup(db, user);
db = CreateContext();
var manager = CreateManager(db);
var userByEmail = await manager.FindByEmailAsync(user.Email);
Assert.Equal(2, (await manager.GetClaimsAsync(userByEmail)).Count);
Assert.Equal(1, (await manager.GetLoginsAsync(userByEmail)).Count);
Assert.Equal(2, (await manager.GetRolesAsync(userByEmail)).Count);
}
}
}

View File

@ -7,15 +7,19 @@ using System.Linq;
using System.Linq.Expressions;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity.Test;
using Microsoft.AspNetCore.Testing;
using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Xunit;
namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test
{
// TODO: Add test variation with non IdentityDbContext
public abstract class SqlStoreTestBase<TUser, TRole, TKey> : IdentitySpecificationTestBase<TUser, TRole, TKey>, IClassFixture<ScratchDatabaseFixture>
where TUser : IdentityUser<TKey>, new()
where TRole : IdentityRole<TKey>, new()
@ -28,6 +32,25 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test
_fixture = fixture;
}
protected override void SetupIdentityServices(IServiceCollection services, object context)
{
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<TestDbContext>((TestDbContext)context);
services.AddLogging();
services.AddSingleton<ILogger<UserManager<TUser>>>(new TestLogger<UserManager<TUser>>());
services.AddSingleton<ILogger<RoleManager<TRole>>>(new TestLogger<RoleManager<TRole>>());
services.AddIdentity<TUser, TRole>(options =>
{
options.Password.RequireDigit = false;
options.Password.RequireLowercase = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.User.AllowedUserNameCharacters = null;
})
.AddDefaultTokenProviders()
.AddEntityFrameworkStores<TestDbContext>();
}
protected override bool ShouldSkipDbTests()
{
return TestPlatformHelper.IsMono || !TestPlatformHelper.IsWindows;
@ -363,6 +386,5 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test
Assert.Equal(1, (await manager.GetLoginsAsync(userByEmail)).Count);
Assert.Equal(2, (await manager.GetRolesAsync(userByEmail)).Count);
}
}
}

View File

@ -101,15 +101,6 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test
Assert.Contains("AddEntityFrameworkStores", e.Message);
}
[Fact]
public void AddEntityFrameworkStoresWithMismatchedUserRoleThrows()
{
var services = new ServiceCollection();
var builder = services.AddIdentity<IdentityUserWithGenerics, IdentityRole>();
var e = Assert.Throws<ArgumentException>(() => builder.AddEntityFrameworkStores<ContextWithGenerics>());
Assert.Contains("violates the constraint of type 'TRole'", e.Message);
}
[Fact]
public async Task CanAddRemoveUserClaimWithIssuer()
{
@ -218,7 +209,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test
#region Generic Type defintions
public class IdentityUserWithGenerics : IdentityUser<string, IdentityUserClaimWithIssuer, IdentityUserRoleWithDate, IdentityUserLoginWithContext, IdentityUserTokenWithStuff>
public class IdentityUserWithGenerics : IdentityUser<string>
{
public IdentityUserWithGenerics()
{
@ -328,7 +319,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test
public DateTime Created { get; set; }
}
public class MyIdentityRole : IdentityRole<string, IdentityUserRoleWithDate, IdentityRoleClaimWithIssuer>
public class MyIdentityRole : IdentityRole<string>
{
public MyIdentityRole() : base()
{

View File

@ -12,302 +12,13 @@ using Microsoft.AspNetCore.Identity.Test;
namespace Microsoft.AspNetCore.Identity.InMemory
{
public class InMemoryStore<TUser, TRole> :
IUserLoginStore<TUser>,
InMemoryUserStore<TUser>,
IUserRoleStore<TUser>,
IUserClaimStore<TUser>,
IUserPasswordStore<TUser>,
IUserSecurityStampStore<TUser>,
IUserEmailStore<TUser>,
IUserLockoutStore<TUser>,
IUserPhoneNumberStore<TUser>,
IQueryableUserStore<TUser>,
IUserTwoFactorStore<TUser>,
IQueryableRoleStore<TRole>,
IRoleClaimStore<TRole>,
IUserAuthenticationTokenStore<TUser>,
IUserAuthenticatorKeyStore<TUser>,
IUserTwoFactorRecoveryCodeStore<TUser>
IRoleClaimStore<TRole>
where TRole : TestRole
where TUser : TestUser
{
private readonly Dictionary<string, TUser> _logins = new Dictionary<string, TUser>();
private readonly Dictionary<string, TUser> _users = new Dictionary<string, TUser>();
public IQueryable<TUser> Users
{
get { return _users.Values.AsQueryable(); }
}
public Task<IList<Claim>> GetClaimsAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
var claims = user.Claims.Select(c => new Claim(c.ClaimType, c.ClaimValue)).ToList();
return Task.FromResult<IList<Claim>>(claims);
}
public Task AddClaimsAsync(TUser user, IEnumerable<Claim> claims, CancellationToken cancellationToken = default(CancellationToken))
{
foreach (var claim in claims)
{
user.Claims.Add(new TestUserClaim { ClaimType = claim.Type, ClaimValue = claim.Value, UserId = user.Id });
}
return Task.FromResult(0);
}
public Task ReplaceClaimAsync(TUser user, Claim claim, Claim newClaim, CancellationToken cancellationToken = default(CancellationToken))
{
var matchedClaims = user.Claims.Where(uc => uc.ClaimValue == claim.Value && uc.ClaimType == claim.Type).ToList();
foreach (var matchedClaim in matchedClaims)
{
matchedClaim.ClaimValue = newClaim.Value;
matchedClaim.ClaimType = newClaim.Type;
}
return Task.FromResult(0);
}
public Task RemoveClaimsAsync(TUser user, IEnumerable<Claim> claims, CancellationToken cancellationToken = default(CancellationToken))
{
foreach (var claim in claims)
{
var entity =
user.Claims.FirstOrDefault(
uc => uc.UserId == user.Id && uc.ClaimType == claim.Type && uc.ClaimValue == claim.Value);
if (entity != null)
{
user.Claims.Remove(entity);
}
}
return Task.FromResult(0);
}
public Task SetEmailAsync(TUser user, string email, CancellationToken cancellationToken = default(CancellationToken))
{
user.Email = email;
return Task.FromResult(0);
}
public Task<string> GetEmailAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.Email);
}
public Task<string> GetNormalizedEmailAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.NormalizedEmail);
}
public Task SetNormalizedEmailAsync(TUser user, string normalizedEmail, CancellationToken cancellationToken = default(CancellationToken))
{
user.NormalizedEmail = normalizedEmail;
return Task.FromResult(0);
}
public Task<bool> GetEmailConfirmedAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.EmailConfirmed);
}
public Task SetEmailConfirmedAsync(TUser user, bool confirmed, CancellationToken cancellationToken = default(CancellationToken))
{
user.EmailConfirmed = confirmed;
return Task.FromResult(0);
}
public Task<TUser> FindByEmailAsync(string email, CancellationToken cancellationToken = default(CancellationToken))
{
return
Task.FromResult(
Users.FirstOrDefault(u => u.NormalizedEmail == email));
}
public Task<DateTimeOffset?> GetLockoutEndDateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.LockoutEnd);
}
public Task SetLockoutEndDateAsync(TUser user, DateTimeOffset? lockoutEnd, CancellationToken cancellationToken = default(CancellationToken))
{
user.LockoutEnd = lockoutEnd;
return Task.FromResult(0);
}
public Task<int> IncrementAccessFailedCountAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
user.AccessFailedCount++;
return Task.FromResult(user.AccessFailedCount);
}
public Task ResetAccessFailedCountAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
user.AccessFailedCount = 0;
return Task.FromResult(0);
}
public Task<int> GetAccessFailedCountAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.AccessFailedCount);
}
public Task<bool> GetLockoutEnabledAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.LockoutEnabled);
}
public Task SetLockoutEnabledAsync(TUser user, bool enabled, CancellationToken cancellationToken = default(CancellationToken))
{
user.LockoutEnabled = enabled;
return Task.FromResult(0);
}
private string GetLoginKey(string loginProvider, string providerKey)
{
return loginProvider + "|" + providerKey;
}
public virtual Task AddLoginAsync(TUser user, UserLoginInfo login,
CancellationToken cancellationToken = default(CancellationToken))
{
user.Logins.Add(new TestUserLogin
{
UserId = user.Id,
ProviderKey = login.ProviderKey,
LoginProvider = login.LoginProvider,
ProviderDisplayName = login.ProviderDisplayName
});
_logins[GetLoginKey(login.LoginProvider, login.ProviderKey)] = user;
return Task.FromResult(0);
}
public Task RemoveLoginAsync(TUser user, string loginProvider, string providerKey,
CancellationToken cancellationToken = default(CancellationToken))
{
var loginEntity =
user.Logins.SingleOrDefault(
l =>
l.ProviderKey == providerKey && l.LoginProvider == loginProvider &&
l.UserId == user.Id);
if (loginEntity != null)
{
user.Logins.Remove(loginEntity);
}
_logins[GetLoginKey(loginProvider, providerKey)] = null;
return Task.FromResult(0);
}
public Task<IList<UserLoginInfo>> GetLoginsAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
IList<UserLoginInfo> result = user.Logins
.Select(l => new UserLoginInfo(l.LoginProvider, l.ProviderKey, l.ProviderDisplayName)).ToList();
return Task.FromResult(result);
}
public Task<TUser> FindByLoginAsync(string loginProvider, string providerKey, CancellationToken cancellationToken = default(CancellationToken))
{
string key = GetLoginKey(loginProvider, providerKey);
if (_logins.ContainsKey(key))
{
return Task.FromResult(_logins[key]);
}
return Task.FromResult<TUser>(null);
}
public Task<string> GetUserIdAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.Id);
}
public Task<string> GetUserNameAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.UserName);
}
public Task SetUserNameAsync(TUser user, string userName, CancellationToken cancellationToken = default(CancellationToken))
{
user.UserName = userName;
return Task.FromResult(0);
}
public Task<IdentityResult> CreateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
_users[user.Id] = user;
return Task.FromResult(IdentityResult.Success);
}
public Task<IdentityResult> UpdateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
_users[user.Id] = user;
return Task.FromResult(IdentityResult.Success);
}
public Task<TUser> FindByIdAsync(string userId, CancellationToken cancellationToken = default(CancellationToken))
{
if (_users.ContainsKey(userId))
{
return Task.FromResult(_users[userId]);
}
return Task.FromResult<TUser>(null);
}
public void Dispose()
{
}
public Task<TUser> FindByNameAsync(string userName, CancellationToken cancellationToken = default(CancellationToken))
{
return
Task.FromResult(
Users.FirstOrDefault(u => u.NormalizedUserName == userName));
}
public Task<IdentityResult> DeleteAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
if (user == null || !_users.ContainsKey(user.Id))
{
throw new InvalidOperationException("Unknown user");
}
_users.Remove(user.Id);
return Task.FromResult(IdentityResult.Success);
}
public Task SetPasswordHashAsync(TUser user, string passwordHash, CancellationToken cancellationToken = default(CancellationToken))
{
user.PasswordHash = passwordHash;
return Task.FromResult(0);
}
public Task<string> GetPasswordHashAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.PasswordHash);
}
public Task<bool> HasPasswordAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.PasswordHash != null);
}
public Task SetPhoneNumberAsync(TUser user, string phoneNumber, CancellationToken cancellationToken = default(CancellationToken))
{
user.PhoneNumber = phoneNumber;
return Task.FromResult(0);
}
public Task<string> GetPhoneNumberAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.PhoneNumber);
}
public Task<bool> GetPhoneNumberConfirmedAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.PhoneNumberConfirmed);
}
public Task SetPhoneNumberConfirmedAsync(TUser user, bool confirmed, CancellationToken cancellationToken = default(CancellationToken))
{
user.PhoneNumberConfirmed = confirmed;
return Task.FromResult(0);
}
// RoleId == roleName for InMemory
public Task AddToRoleAsync(TUser user, string role, CancellationToken cancellationToken = default(CancellationToken))
{
@ -348,39 +59,6 @@ namespace Microsoft.AspNetCore.Identity.InMemory
return Task.FromResult(result);
}
public Task SetSecurityStampAsync(TUser user, string stamp, CancellationToken cancellationToken = default(CancellationToken))
{
user.SecurityStamp = stamp;
return Task.FromResult(0);
}
public Task<string> GetSecurityStampAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.SecurityStamp);
}
public Task SetTwoFactorEnabledAsync(TUser user, bool enabled, CancellationToken cancellationToken = default(CancellationToken))
{
user.TwoFactorEnabled = enabled;
return Task.FromResult(0);
}
public Task<bool> GetTwoFactorEnabledAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.TwoFactorEnabled);
}
public Task<string> GetNormalizedUserNameAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.NormalizedUserName);
}
public Task SetNormalizedUserNameAsync(TUser user, string userName, CancellationToken cancellationToken = default(CancellationToken))
{
user.NormalizedUserName = userName;
return Task.FromResult(0);
}
// RoleId == rolename for inmemory store tests
public Task<IList<TUser>> GetUsersInRoleAsync(string roleName, CancellationToken cancellationToken = default(CancellationToken))
{
@ -397,20 +75,6 @@ namespace Microsoft.AspNetCore.Identity.InMemory
return Task.FromResult<IList<TUser>>(Users.Where(u => (u.Roles.Where(x => x.RoleId == role.Id).Count() > 0)).Select(x => x).ToList());
}
public Task<IList<TUser>> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken = default(CancellationToken))
{
if (claim == null)
{
throw new ArgumentNullException(nameof(claim));
}
var query = from user in Users
where user.Claims.Where(x => x.ClaimType == claim.Type && x.ClaimValue == claim.Value).FirstOrDefault() != null
select user;
return Task.FromResult<IList<TUser>>(query.ToList());
}
private readonly Dictionary<string, TRole> _roles = new Dictionary<string, TRole>();
public Task<IdentityResult> CreateAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken))
@ -502,87 +166,6 @@ namespace Microsoft.AspNetCore.Identity.InMemory
return Task.FromResult(0);
}
public Task SetTokenAsync(TUser user, string loginProvider, string name, string value, CancellationToken cancellationToken)
{
var tokenEntity =
user.Tokens.SingleOrDefault(
l =>
l.TokenName == name && l.LoginProvider == loginProvider &&
l.UserId == user.Id);
if (tokenEntity != null)
{
tokenEntity.TokenValue = value;
}
else
{
user.Tokens.Add(new TestUserToken
{
UserId = user.Id,
LoginProvider = loginProvider,
TokenName = name,
TokenValue = value
});
}
return Task.FromResult(0);
}
public Task RemoveTokenAsync(TUser user, string loginProvider, string name, CancellationToken cancellationToken)
{
var tokenEntity =
user.Tokens.SingleOrDefault(
l =>
l.TokenName == name && l.LoginProvider == loginProvider &&
l.UserId == user.Id);
if (tokenEntity != null)
{
user.Tokens.Remove(tokenEntity);
}
return Task.FromResult(0);
}
public Task<string> GetTokenAsync(TUser user, string loginProvider, string name, CancellationToken cancellationToken)
{
var tokenEntity =
user.Tokens.SingleOrDefault(
l =>
l.TokenName == name && l.LoginProvider == loginProvider &&
l.UserId == user.Id);
return Task.FromResult(tokenEntity?.TokenValue);
}
private const string AuthenticatorStoreLoginProvider = "[AspNetAuthenticatorStore]";
private const string AuthenticatorKeyTokenName = "AuthenticatorKey";
private const string RecoveryCodeTokenName = "RecoveryCodes";
public Task SetAuthenticatorKeyAsync(TUser user, string key, CancellationToken cancellationToken)
{
return SetTokenAsync(user, AuthenticatorStoreLoginProvider, AuthenticatorKeyTokenName, key, cancellationToken);
}
public Task<string> GetAuthenticatorKeyAsync(TUser user, CancellationToken cancellationToken)
{
return GetTokenAsync(user, AuthenticatorStoreLoginProvider, AuthenticatorKeyTokenName, cancellationToken);
}
public Task ReplaceCodesAsync(TUser user, IEnumerable<string> recoveryCodes, CancellationToken cancellationToken)
{
var mergedCodes = string.Join(";", recoveryCodes);
return SetTokenAsync(user, AuthenticatorStoreLoginProvider, RecoveryCodeTokenName, mergedCodes, cancellationToken);
}
public async Task<bool> RedeemCodeAsync(TUser user, string code, CancellationToken cancellationToken)
{
var mergedCodes = await GetTokenAsync(user, AuthenticatorStoreLoginProvider, RecoveryCodeTokenName, cancellationToken) ?? "";
var splitCodes = mergedCodes.Split(';');
if (splitCodes.Contains(code))
{
var updatedCodes = new List<string>(splitCodes.Where(s => s != code));
await ReplaceCodesAsync(user, updatedCodes, cancellationToken);
return true;
}
return false;
}
public IQueryable<TRole> Roles
{
get { return _roles.Values.AsQueryable(); }

View File

@ -0,0 +1,435 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity.Test;
namespace Microsoft.AspNetCore.Identity.InMemory
{
public class InMemoryUserStore<TUser> :
IUserLoginStore<TUser>,
IUserClaimStore<TUser>,
IUserPasswordStore<TUser>,
IUserSecurityStampStore<TUser>,
IUserEmailStore<TUser>,
IUserLockoutStore<TUser>,
IUserPhoneNumberStore<TUser>,
IQueryableUserStore<TUser>,
IUserTwoFactorStore<TUser>,
IUserAuthenticationTokenStore<TUser>,
IUserAuthenticatorKeyStore<TUser>,
IUserTwoFactorRecoveryCodeStore<TUser>
where TUser : TestUser
{
private readonly Dictionary<string, TUser> _logins = new Dictionary<string, TUser>();
private readonly Dictionary<string, TUser> _users = new Dictionary<string, TUser>();
public IQueryable<TUser> Users
{
get { return _users.Values.AsQueryable(); }
}
public Task<IList<Claim>> GetClaimsAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
var claims = user.Claims.Select(c => new Claim(c.ClaimType, c.ClaimValue)).ToList();
return Task.FromResult<IList<Claim>>(claims);
}
public Task AddClaimsAsync(TUser user, IEnumerable<Claim> claims, CancellationToken cancellationToken = default(CancellationToken))
{
foreach (var claim in claims)
{
user.Claims.Add(new TestUserClaim { ClaimType = claim.Type, ClaimValue = claim.Value, UserId = user.Id });
}
return Task.FromResult(0);
}
public Task ReplaceClaimAsync(TUser user, Claim claim, Claim newClaim, CancellationToken cancellationToken = default(CancellationToken))
{
var matchedClaims = user.Claims.Where(uc => uc.ClaimValue == claim.Value && uc.ClaimType == claim.Type).ToList();
foreach (var matchedClaim in matchedClaims)
{
matchedClaim.ClaimValue = newClaim.Value;
matchedClaim.ClaimType = newClaim.Type;
}
return Task.FromResult(0);
}
public Task RemoveClaimsAsync(TUser user, IEnumerable<Claim> claims, CancellationToken cancellationToken = default(CancellationToken))
{
foreach (var claim in claims)
{
var entity =
user.Claims.FirstOrDefault(
uc => uc.UserId == user.Id && uc.ClaimType == claim.Type && uc.ClaimValue == claim.Value);
if (entity != null)
{
user.Claims.Remove(entity);
}
}
return Task.FromResult(0);
}
public Task SetEmailAsync(TUser user, string email, CancellationToken cancellationToken = default(CancellationToken))
{
user.Email = email;
return Task.FromResult(0);
}
public Task<string> GetEmailAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.Email);
}
public Task<string> GetNormalizedEmailAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.NormalizedEmail);
}
public Task SetNormalizedEmailAsync(TUser user, string normalizedEmail, CancellationToken cancellationToken = default(CancellationToken))
{
user.NormalizedEmail = normalizedEmail;
return Task.FromResult(0);
}
public Task<bool> GetEmailConfirmedAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.EmailConfirmed);
}
public Task SetEmailConfirmedAsync(TUser user, bool confirmed, CancellationToken cancellationToken = default(CancellationToken))
{
user.EmailConfirmed = confirmed;
return Task.FromResult(0);
}
public Task<TUser> FindByEmailAsync(string email, CancellationToken cancellationToken = default(CancellationToken))
{
return
Task.FromResult(
Users.FirstOrDefault(u => u.NormalizedEmail == email));
}
public Task<DateTimeOffset?> GetLockoutEndDateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.LockoutEnd);
}
public Task SetLockoutEndDateAsync(TUser user, DateTimeOffset? lockoutEnd, CancellationToken cancellationToken = default(CancellationToken))
{
user.LockoutEnd = lockoutEnd;
return Task.FromResult(0);
}
public Task<int> IncrementAccessFailedCountAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
user.AccessFailedCount++;
return Task.FromResult(user.AccessFailedCount);
}
public Task ResetAccessFailedCountAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
user.AccessFailedCount = 0;
return Task.FromResult(0);
}
public Task<int> GetAccessFailedCountAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.AccessFailedCount);
}
public Task<bool> GetLockoutEnabledAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.LockoutEnabled);
}
public Task SetLockoutEnabledAsync(TUser user, bool enabled, CancellationToken cancellationToken = default(CancellationToken))
{
user.LockoutEnabled = enabled;
return Task.FromResult(0);
}
private string GetLoginKey(string loginProvider, string providerKey)
{
return loginProvider + "|" + providerKey;
}
public virtual Task AddLoginAsync(TUser user, UserLoginInfo login,
CancellationToken cancellationToken = default(CancellationToken))
{
user.Logins.Add(new TestUserLogin
{
UserId = user.Id,
ProviderKey = login.ProviderKey,
LoginProvider = login.LoginProvider,
ProviderDisplayName = login.ProviderDisplayName
});
_logins[GetLoginKey(login.LoginProvider, login.ProviderKey)] = user;
return Task.FromResult(0);
}
public Task RemoveLoginAsync(TUser user, string loginProvider, string providerKey,
CancellationToken cancellationToken = default(CancellationToken))
{
var loginEntity =
user.Logins.SingleOrDefault(
l =>
l.ProviderKey == providerKey && l.LoginProvider == loginProvider &&
l.UserId == user.Id);
if (loginEntity != null)
{
user.Logins.Remove(loginEntity);
}
_logins[GetLoginKey(loginProvider, providerKey)] = null;
return Task.FromResult(0);
}
public Task<IList<UserLoginInfo>> GetLoginsAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
IList<UserLoginInfo> result = user.Logins
.Select(l => new UserLoginInfo(l.LoginProvider, l.ProviderKey, l.ProviderDisplayName)).ToList();
return Task.FromResult(result);
}
public Task<TUser> FindByLoginAsync(string loginProvider, string providerKey, CancellationToken cancellationToken = default(CancellationToken))
{
string key = GetLoginKey(loginProvider, providerKey);
if (_logins.ContainsKey(key))
{
return Task.FromResult(_logins[key]);
}
return Task.FromResult<TUser>(null);
}
public Task<string> GetUserIdAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.Id);
}
public Task<string> GetUserNameAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.UserName);
}
public Task SetUserNameAsync(TUser user, string userName, CancellationToken cancellationToken = default(CancellationToken))
{
user.UserName = userName;
return Task.FromResult(0);
}
public Task<IdentityResult> CreateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
_users[user.Id] = user;
return Task.FromResult(IdentityResult.Success);
}
public Task<IdentityResult> UpdateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
_users[user.Id] = user;
return Task.FromResult(IdentityResult.Success);
}
public Task<TUser> FindByIdAsync(string userId, CancellationToken cancellationToken = default(CancellationToken))
{
if (_users.ContainsKey(userId))
{
return Task.FromResult(_users[userId]);
}
return Task.FromResult<TUser>(null);
}
public void Dispose()
{
}
public Task<TUser> FindByNameAsync(string userName, CancellationToken cancellationToken = default(CancellationToken))
{
return
Task.FromResult(
Users.FirstOrDefault(u => u.NormalizedUserName == userName));
}
public Task<IdentityResult> DeleteAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
if (user == null || !_users.ContainsKey(user.Id))
{
throw new InvalidOperationException("Unknown user");
}
_users.Remove(user.Id);
return Task.FromResult(IdentityResult.Success);
}
public Task SetPasswordHashAsync(TUser user, string passwordHash, CancellationToken cancellationToken = default(CancellationToken))
{
user.PasswordHash = passwordHash;
return Task.FromResult(0);
}
public Task<string> GetPasswordHashAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.PasswordHash);
}
public Task<bool> HasPasswordAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.PasswordHash != null);
}
public Task SetPhoneNumberAsync(TUser user, string phoneNumber, CancellationToken cancellationToken = default(CancellationToken))
{
user.PhoneNumber = phoneNumber;
return Task.FromResult(0);
}
public Task<string> GetPhoneNumberAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.PhoneNumber);
}
public Task<bool> GetPhoneNumberConfirmedAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.PhoneNumberConfirmed);
}
public Task SetPhoneNumberConfirmedAsync(TUser user, bool confirmed, CancellationToken cancellationToken = default(CancellationToken))
{
user.PhoneNumberConfirmed = confirmed;
return Task.FromResult(0);
}
public Task SetSecurityStampAsync(TUser user, string stamp, CancellationToken cancellationToken = default(CancellationToken))
{
user.SecurityStamp = stamp;
return Task.FromResult(0);
}
public Task<string> GetSecurityStampAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.SecurityStamp);
}
public Task SetTwoFactorEnabledAsync(TUser user, bool enabled, CancellationToken cancellationToken = default(CancellationToken))
{
user.TwoFactorEnabled = enabled;
return Task.FromResult(0);
}
public Task<bool> GetTwoFactorEnabledAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.TwoFactorEnabled);
}
public Task<string> GetNormalizedUserNameAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.FromResult(user.NormalizedUserName);
}
public Task SetNormalizedUserNameAsync(TUser user, string userName, CancellationToken cancellationToken = default(CancellationToken))
{
user.NormalizedUserName = userName;
return Task.FromResult(0);
}
public Task<IList<TUser>> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken = default(CancellationToken))
{
if (claim == null)
{
throw new ArgumentNullException(nameof(claim));
}
var query = from user in Users
where user.Claims.Where(x => x.ClaimType == claim.Type && x.ClaimValue == claim.Value).FirstOrDefault() != null
select user;
return Task.FromResult<IList<TUser>>(query.ToList());
}
public Task SetTokenAsync(TUser user, string loginProvider, string name, string value, CancellationToken cancellationToken)
{
var tokenEntity =
user.Tokens.SingleOrDefault(
l =>
l.TokenName == name && l.LoginProvider == loginProvider &&
l.UserId == user.Id);
if (tokenEntity != null)
{
tokenEntity.TokenValue = value;
}
else
{
user.Tokens.Add(new TestUserToken
{
UserId = user.Id,
LoginProvider = loginProvider,
TokenName = name,
TokenValue = value
});
}
return Task.FromResult(0);
}
public Task RemoveTokenAsync(TUser user, string loginProvider, string name, CancellationToken cancellationToken)
{
var tokenEntity =
user.Tokens.SingleOrDefault(
l =>
l.TokenName == name && l.LoginProvider == loginProvider &&
l.UserId == user.Id);
if (tokenEntity != null)
{
user.Tokens.Remove(tokenEntity);
}
return Task.FromResult(0);
}
public Task<string> GetTokenAsync(TUser user, string loginProvider, string name, CancellationToken cancellationToken)
{
var tokenEntity =
user.Tokens.SingleOrDefault(
l =>
l.TokenName == name && l.LoginProvider == loginProvider &&
l.UserId == user.Id);
return Task.FromResult(tokenEntity?.TokenValue);
}
private const string AuthenticatorStoreLoginProvider = "[AspNetAuthenticatorStore]";
private const string AuthenticatorKeyTokenName = "AuthenticatorKey";
private const string RecoveryCodeTokenName = "RecoveryCodes";
public Task SetAuthenticatorKeyAsync(TUser user, string key, CancellationToken cancellationToken)
{
return SetTokenAsync(user, AuthenticatorStoreLoginProvider, AuthenticatorKeyTokenName, key, cancellationToken);
}
public Task<string> GetAuthenticatorKeyAsync(TUser user, CancellationToken cancellationToken)
{
return GetTokenAsync(user, AuthenticatorStoreLoginProvider, AuthenticatorKeyTokenName, cancellationToken);
}
public Task ReplaceCodesAsync(TUser user, IEnumerable<string> recoveryCodes, CancellationToken cancellationToken)
{
var mergedCodes = string.Join(";", recoveryCodes);
return SetTokenAsync(user, AuthenticatorStoreLoginProvider, RecoveryCodeTokenName, mergedCodes, cancellationToken);
}
public async Task<bool> RedeemCodeAsync(TUser user, string code, CancellationToken cancellationToken)
{
var mergedCodes = await GetTokenAsync(user, AuthenticatorStoreLoginProvider, RecoveryCodeTokenName, cancellationToken) ?? "";
var splitCodes = mergedCodes.Split(';');
if (splitCodes.Contains(code))
{
var updatedCodes = new List<string>(splitCodes.Where(s => s != code));
await ReplaceCodesAsync(user, updatedCodes, cancellationToken);
return true;
}
return false;
}
}
}

View File

@ -0,0 +1,45 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq.Expressions;
using Microsoft.AspNetCore.Identity.Test;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Identity.InMemory.Test
{
public class InMemoryUserStoreTest : UserManagerSpecificationTestBase<TestUser, string>
{
protected override object CreateTestContext()
{
return new InMemoryUserStore<TestUser>();
}
protected override void AddUserStore(IServiceCollection services, object context = null)
{
services.AddSingleton<IUserStore<TestUser>>((InMemoryUserStore<TestUser>)context);
}
protected override void SetUserPasswordHash(TestUser user, string hashedPassword)
{
user.PasswordHash = hashedPassword;
}
protected override TestUser CreateTestUser(string namePrefix = "", string email = "", string phoneNumber = "",
bool lockoutEnabled = false, DateTimeOffset? lockoutEnd = default(DateTimeOffset?), bool useNamePrefixAsUserName = false)
{
return new TestUser
{
UserName = useNamePrefixAsUserName ? namePrefix : string.Format("{0}{1}", namePrefix, Guid.NewGuid()),
Email = email,
PhoneNumber = phoneNumber,
LockoutEnabled = lockoutEnabled,
LockoutEnd = lockoutEnd
};
}
protected override Expression<Func<TestUser, bool>> UserNameEqualsPredicate(string userName) => u => u.UserName == userName;
protected override Expression<Func<TestUser, bool>> UserNameStartsWithPredicate(string userName) => u => u.UserName.StartsWith(userName);
}
}

View File

@ -53,8 +53,8 @@ namespace Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore.InMemory.Tes
TRedirectUri,
TApplicationKey> :
IdentityServiceDbContext<TUser, TRole, TUserKey, TUserClaim, TUserRole, TUserLogin, TRoleClaim, TUserToken, TApplication, TScope, TApplicationClaim, TRedirectUri, TApplicationKey>
where TUser : IdentityUser<TUserKey, TUserClaim, TUserRole, TUserLogin, TUserToken>
where TRole : IdentityRole<TUserKey, TUserRole, TRoleClaim>
where TUser : IdentityUser<TUserKey>
where TRole : IdentityRole<TUserKey>
where TUserKey : IEquatable<TUserKey>
where TUserClaim : IdentityUserClaim<TUserKey>
where TUserRole : IdentityUserRole<TUserKey>

View File

@ -160,9 +160,6 @@ namespace Microsoft.AspNetCore.Identity.Test
var services = new ServiceCollection()
.AddSingleton<IConfiguration>(new ConfigurationBuilder().Build());
var builder = services.AddIdentity<TestUser, TestRole>();
Assert.Throws<InvalidOperationException>(() => builder.AddUserManager<UserManager<TestUser>>());
Assert.Throws<InvalidOperationException>(() => builder.AddRoleManager<RoleManager<TestRole>>());
Assert.Throws<InvalidOperationException>(() => builder.AddSignInManager<SignInManager<TestRole>>());
Assert.Throws<InvalidOperationException>(() => builder.AddUserManager<object>());
Assert.Throws<InvalidOperationException>(() => builder.AddRoleManager<object>());
Assert.Throws<InvalidOperationException>(() => builder.AddSignInManager<object>());

View File

@ -499,7 +499,7 @@ namespace Microsoft.AspNetCore.Identity.Test
// Act
// Assert
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => manager.CreateAsync(user));
Assert.Contains(Resources.NullSecurityStamp, ex.Message);
Assert.Contains(Extensions.Identity.Core.Resources.NullSecurityStamp, ex.Message);
store.VerifyAll();
}
@ -516,7 +516,7 @@ namespace Microsoft.AspNetCore.Identity.Test
// Act
// Assert
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => manager.UpdateAsync(user));
Assert.Contains(Resources.NullSecurityStamp, ex.Message);
Assert.Contains(Extensions.Identity.Core.Resources.NullSecurityStamp, ex.Message);
store.VerifyAll();
}
@ -698,146 +698,6 @@ namespace Microsoft.AspNetCore.Identity.Test
Assert.ThrowsAsync<NotImplementedException>(() => manager.GenerateUserTokenAsync(new TestUser(), "A", "purpose"));
}
[Fact]
public void TOTPTest()
{
//var verify = new TotpAuthenticatorVerification();
//var secret = "abcdefghij";
//var secret = Base32.FromBase32(authKey);
// Assert.Equal(bytes, secret);
//var code = verify.VerifyCode(secret, -1);
//Assert.Equal(code, 287004);
//var bytes = new byte[] { (byte)'H', (byte)'e', (byte)'l', (byte)'l', (byte)'o', (byte)'!', (byte)0xDE, (byte)0xAD, (byte)0xBE, (byte)0xEF };
//var base32 = Base32.ToBase32(bytes);
// var code = Rfc6238AuthenticationService.GenerateCode(bytes);
// Assert.Equal(Rfc6238AuthenticationService.GenerateCode(bytes), Rfc6238AuthenticationService.CalculateOneTimePassword(new HMACSHA1(bytes)));
//Assert.True(Rfc6238AuthenticationService.ValidateCode(bytes, code));
}
public static byte[] ToBytes(string input)
{
if (string.IsNullOrEmpty(input))
{
throw new ArgumentNullException("input");
}
input = input.TrimEnd('='); //remove padding characters
int byteCount = input.Length * 5 / 8; //this must be TRUNCATED
byte[] returnArray = new byte[byteCount];
byte curByte = 0, bitsRemaining = 8;
int mask = 0, arrayIndex = 0;
foreach (char c in input)
{
int cValue = CharToValue(c);
if (bitsRemaining > 5)
{
mask = cValue << (bitsRemaining - 5);
curByte = (byte)(curByte | mask);
bitsRemaining -= 5;
}
else
{
mask = cValue >> (5 - bitsRemaining);
curByte = (byte)(curByte | mask);
returnArray[arrayIndex++] = curByte;
curByte = (byte)(cValue << (3 + bitsRemaining));
bitsRemaining += 3;
}
}
//if we didn't end with a full byte
if (arrayIndex != byteCount)
{
returnArray[arrayIndex] = curByte;
}
return returnArray;
}
public static string ToString(byte[] input)
{
if (input == null || input.Length == 0)
{
throw new ArgumentNullException("input");
}
int charCount = (int)Math.Ceiling(input.Length / 5d) * 8;
char[] returnArray = new char[charCount];
byte nextChar = 0, bitsRemaining = 5;
int arrayIndex = 0;
foreach (byte b in input)
{
nextChar = (byte)(nextChar | (b >> (8 - bitsRemaining)));
returnArray[arrayIndex++] = ValueToChar(nextChar);
if (bitsRemaining < 4)
{
nextChar = (byte)((b >> (3 - bitsRemaining)) & 31);
returnArray[arrayIndex++] = ValueToChar(nextChar);
bitsRemaining += 5;
}
bitsRemaining -= 3;
nextChar = (byte)((b << bitsRemaining) & 31);
}
//if we didn't end with a full char
if (arrayIndex != charCount)
{
returnArray[arrayIndex++] = ValueToChar(nextChar);
while (arrayIndex != charCount) returnArray[arrayIndex++] = '='; //padding
}
return new string(returnArray);
}
private static int CharToValue(char c)
{
var value = (int)c;
//65-90 == uppercase letters
if (value < 91 && value > 64)
{
return value - 65;
}
//50-55 == numbers 2-7
if (value < 56 && value > 49)
{
return value - 24;
}
//97-122 == lowercase letters
if (value < 123 && value > 96)
{
return value - 97;
}
throw new ArgumentException("Character is not a Base32 character.", "c");
}
private static char ValueToChar(byte b)
{
if (b < 26)
{
return (char)(b + 65);
}
if (b < 32)
{
return (char)(b + 24);
}
throw new ArgumentException("Byte is not a value Base32 value.", "b");
}
[Fact]
public void UserManagerWillUseTokenProviderInstanceOverDefaults()
{
@ -894,7 +754,7 @@ namespace Microsoft.AspNetCore.Identity.Test
[Fact]
public async Task AuthTokenMethodsFailWhenStoreNotImplemented()
{
var error = Resources.StoreNotIUserAuthenticationTokenStore;
var error = Extensions.Identity.Core.Resources.StoreNotIUserAuthenticationTokenStore;
var manager = MockHelpers.TestUserManager(new NoopUserStore());
Assert.False(manager.SupportsUserAuthenticationTokens);
await VerifyException<NotSupportedException>(async () => await manager.GetAuthenticationTokenAsync(null, null, null), error);
@ -905,7 +765,7 @@ namespace Microsoft.AspNetCore.Identity.Test
[Fact]
public async Task AuthenticatorMethodsFailWhenStoreNotImplemented()
{
var error = Resources.StoreNotIUserAuthenticatorKeyStore;
var error = Extensions.Identity.Core.Resources.StoreNotIUserAuthenticatorKeyStore;
var manager = MockHelpers.TestUserManager(new NoopUserStore());
Assert.False(manager.SupportsUserAuthenticatorKey);
await VerifyException<NotSupportedException>(async () => await manager.GetAuthenticatorKeyAsync(null), error);
@ -915,7 +775,7 @@ namespace Microsoft.AspNetCore.Identity.Test
[Fact]
public async Task RecoveryMethodsFailWhenStoreNotImplemented()
{
var error = Resources.StoreNotIUserTwoFactorRecoveryCodeStore;
var error = Extensions.Identity.Core.Resources.StoreNotIUserTwoFactorRecoveryCodeStore;
var manager = MockHelpers.TestUserManager(new NoopUserStore());
Assert.False(manager.SupportsUserTwoFactorRecoveryCodes);
await VerifyException<NotSupportedException>(async () => await manager.RedeemTwoFactorRecoveryCodeAsync(null, null), error);