From ace88b21be285a4e67dfa112eb74068d3782513f Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Wed, 7 May 2014 17:29:06 -0700 Subject: [PATCH] Add support for UserClaims --- .../IdentitySqlContext.cs | 9 +++- .../SqlUserStore.cs | 50 ++++++++++++++++++- .../IdentityBuilderExtensions.cs | 4 +- .../SqlUserStoreTest.cs | 41 ++++++++++++++- .../StartupTest.cs | 34 +++++++++++++ 5 files changed, 132 insertions(+), 6 deletions(-) diff --git a/src/Microsoft.AspNet.Identity.Entity/IdentitySqlContext.cs b/src/Microsoft.AspNet.Identity.Entity/IdentitySqlContext.cs index 16641957ba..2c9c482d99 100644 --- a/src/Microsoft.AspNet.Identity.Entity/IdentitySqlContext.cs +++ b/src/Microsoft.AspNet.Identity.Entity/IdentitySqlContext.cs @@ -36,6 +36,7 @@ namespace Microsoft.AspNet.Identity.Entity { public DbSet Users { get; set; } + public DbSet UserClaims { get; set; } //public DbSet Roles { get; set; } public IdentitySqlContext(IServiceProvider serviceProvider) @@ -46,7 +47,7 @@ namespace Microsoft.AspNet.Identity.Entity protected override void OnConfiguring(DbContextOptions builder) { // TODO: pull connection string from config - builder.UseSqlServer(@"Server=(localdb)\v11.0;Database=SimpleIdentity3;Trusted_Connection=True;"); + builder.UseSqlServer(@"Server=(localdb)\v11.0;Database=SimpleIdentity5;Trusted_Connection=True;"); } protected override void OnModelCreating(ModelBuilder builder) @@ -55,6 +56,12 @@ namespace Microsoft.AspNet.Identity.Entity .Key(u => u.Id) .Properties(ps => ps.Property(u => u.UserName)) .ToTable("AspNetUsers"); + + builder.Entity() + .Key(uc => uc.Id) + // TODO: this throws a length exception currently, investigate + //.ForeignKeys(fk => fk.ForeignKey(f => f.UserId)) + .ToTable("AspNetUserClaims"); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Identity.Entity/SqlUserStore.cs b/src/Microsoft.AspNet.Identity.Entity/SqlUserStore.cs index dbfdcd0065..30a541bdff 100644 --- a/src/Microsoft.AspNet.Identity.Entity/SqlUserStore.cs +++ b/src/Microsoft.AspNet.Identity.Entity/SqlUserStore.cs @@ -37,7 +37,8 @@ namespace Microsoft.AspNet.Identity.Entity public class UserStore : //IUserRoleStore, IUserPasswordStore, - IQueryableUserStore + IQueryableUserStore, + IUserClaimStore where TUser : User { private bool _disposed; @@ -347,5 +348,52 @@ namespace Microsoft.AspNet.Identity.Entity { _disposed = true; } + + private DbSet UserClaims { get { return Context.Set(); } } + + public Task> GetClaimsAsync(TUser user, CancellationToken cancellationToken = new CancellationToken()) + { + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException("user"); + } + IList result = UserClaims.Where(uc => uc.UserId == user.Id).Select(c => new Claim(c.ClaimType, c.ClaimValue)).ToList(); + return Task.FromResult(result); + } + + public Task AddClaimAsync(TUser user, Claim claim, CancellationToken cancellationToken = new CancellationToken()) + { + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException("user"); + } + if (claim == null) + { + throw new ArgumentNullException("claim"); + } + UserClaims.Add(new IdentityUserClaim { UserId = user.Id, ClaimType = claim.Type, ClaimValue = claim.Value }); + return Task.FromResult(0); + } + + public Task RemoveClaimAsync(TUser user, Claim claim, CancellationToken cancellationToken = new CancellationToken()) + { + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException("user"); + } + if (claim == null) + { + throw new ArgumentNullException("claim"); + } + var claims = UserClaims.Where(uc => uc.ClaimValue == claim.Value && uc.ClaimType == claim.Type).ToList(); + foreach (var c in claims) + { + UserClaims.Remove(c); + } + return Task.FromResult(0); + } } } diff --git a/src/Microsoft.AspNet.Identity.InMemory/IdentityBuilderExtensions.cs b/src/Microsoft.AspNet.Identity.InMemory/IdentityBuilderExtensions.cs index 758ea32359..16aa5f0bad 100644 --- a/src/Microsoft.AspNet.Identity.InMemory/IdentityBuilderExtensions.cs +++ b/src/Microsoft.AspNet.Identity.InMemory/IdentityBuilderExtensions.cs @@ -9,9 +9,9 @@ namespace Microsoft.AspNet.Identity where TUser : IdentityUser where TRole : IdentityRole { - builder.Services.AddScoped, InMemoryUserStore>(); + builder.Services.AddSingleton, InMemoryUserStore>(); builder.Services.AddScoped, UserManager>(); - builder.Services.AddScoped, InMemoryRoleStore>(); + builder.Services.AddSingleton, InMemoryRoleStore>(); builder.Services.AddScoped, RoleManager>(); return builder; } diff --git a/test/Microsoft.AspNet.Identity.Entity.Test/SqlUserStoreTest.cs b/test/Microsoft.AspNet.Identity.Entity.Test/SqlUserStoreTest.cs index a34bd72503..11c4a6d154 100644 --- a/test/Microsoft.AspNet.Identity.Entity.Test/SqlUserStoreTest.cs +++ b/test/Microsoft.AspNet.Identity.Entity.Test/SqlUserStoreTest.cs @@ -214,8 +214,8 @@ namespace Microsoft.AspNet.Identity.Entity.Test [Fact] public async Task CanChangePassword() { - var manager = TestIdentityFactory.CreateManager(); - var user = new EntityUser("ChangePasswordTest"); + var manager = CreateManager(); + var user = new User("ChangePasswordTest"); const string password = "password"; const string newPassword = "newpassword"; IdentityResultAssert.IsSuccess(await manager.CreateAsync(user, password)); @@ -229,5 +229,42 @@ namespace Microsoft.AspNet.Identity.Entity.Test IdentityResultAssert.IsSuccess(await manager.DeleteAsync(user)); } + [Fact] + public async Task ClaimsIdentityCreatesExpectedClaims() + { + var manager = CreateManager(); + //var role = TestIdentityFactory.CreateRoleManager(context); + var user = new User("Hao"); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + //IdentityResultAssert.IsSuccess(await role.CreateAsync(new EntityRole("Admin"))); + //IdentityResultAssert.IsSuccess(await role.CreateAsync(new EntityRole("Local"))); + //IdentityResultAssert.IsSuccess(await manager.AddToRoleAsync(user, "Admin")); + //IdentityResultAssert.IsSuccess(await manager.AddToRoleAsync(user, "Local")); + Claim[] userClaims = + { + new Claim("Whatever", "Value"), + new Claim("Whatever2", "Value2") + }; + foreach (var c in userClaims) + { + IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user, c)); + } + + var identity = await manager.CreateIdentityAsync(user, "test"); + var claimsFactory = (ClaimsIdentityFactory)manager.ClaimsIdentityFactory; + Assert.NotNull(claimsFactory); + var claims = identity.Claims.ToList(); + Assert.NotNull(claims); + Assert.True( + claims.Any(c => c.Type == manager.Options.ClaimType.UserName && c.Value == user.UserName)); + Assert.True(claims.Any(c => c.Type == manager.Options.ClaimType.UserId && c.Value == user.Id.ToString())); + //Assert.True(claims.Any(c => c.Type == manager.Options.ClaimType.Role && c.Value == "Admin")); + //Assert.True(claims.Any(c => c.Type == manager.Options.ClaimType.Role && c.Value == "Local")); + foreach (var cl in userClaims) + { + Assert.True(claims.Any(c => c.Type == cl.Type && c.Value == cl.Value)); + } + IdentityResultAssert.IsSuccess(await manager.DeleteAsync(user)); + } } } diff --git a/test/Microsoft.AspNet.Identity.InMemory.Test/StartupTest.cs b/test/Microsoft.AspNet.Identity.InMemory.Test/StartupTest.cs index 5f4696606a..e135b38b5d 100644 --- a/test/Microsoft.AspNet.Identity.InMemory.Test/StartupTest.cs +++ b/test/Microsoft.AspNet.Identity.InMemory.Test/StartupTest.cs @@ -111,6 +111,40 @@ namespace Microsoft.AspNet.Identity.InMemory.Test await CreateAdminUser(builder.ApplicationServices); } + [Fact] + public void VerifyUseInMemoryLifetimes() + { + IBuilder builder = new Microsoft.AspNet.Builder.Builder(new ServiceCollection().BuildServiceProvider()); + builder.UseServices(services => + { + services.AddIdentity(s => s.AddInMemory()); + services.AddTransient(); + services.AddTransient(); + + }); + + var userStore = builder.ApplicationServices.GetService>(); + var roleStore = builder.ApplicationServices.GetService>(); + var userManager = builder.ApplicationServices.GetService(); + var roleManager = builder.ApplicationServices.GetService(); + + Assert.NotNull(userStore); + Assert.NotNull(userManager); + Assert.NotNull(roleStore); + Assert.NotNull(roleManager); + + var userStore2 = builder.ApplicationServices.GetService>(); + var roleStore2 = builder.ApplicationServices.GetService>(); + var userManager2 = builder.ApplicationServices.GetService(); + var roleManager2 = builder.ApplicationServices.GetService(); + + Assert.Equal(userStore, userStore2); + Assert.NotEqual(userManager, userManager2); + Assert.Equal(roleStore, roleStore2); + Assert.NotEqual(roleManager, roleManager2); + } + + private static async Task CreateAdminUser(IServiceProvider serviceProvider) { const string userName = "admin";