Restore support for EF User store generics

This commit is contained in:
Hao Kung 2016-05-23 13:05:12 -07:00
parent 6b6b21a5bf
commit 104f216191
14 changed files with 943 additions and 75 deletions

View File

@ -0,0 +1,19 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:28248/",
"sslPort": 0
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNET_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -3,7 +3,6 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
{
@ -52,7 +51,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// <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>
public class IdentityDbContext<TUser, TRole, TKey> : DbContext
public class IdentityDbContext<TUser, TRole, TKey> : IdentityDbContext<TUser, TRole, TKey, IdentityUserClaim<TKey>, IdentityUserRole<TKey>, IdentityUserLogin<TKey>, IdentityRoleClaim<TKey>, IdentityUserToken<TKey>>
where TUser : IdentityUser<TKey>
where TRole : IdentityRole<TKey>
where TKey : IEquatable<TKey>
@ -69,6 +68,41 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// </summary>
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="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>
where TRole : IdentityRole<TKey, TUserRole, TRoleClaim>
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 <see cref="IdentityDbContext"/>.
/// </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 <see cref="IdentityDbContext" /> class.
/// </summary>
protected IdentityDbContext()
{ }
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of Users.
@ -78,22 +112,22 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of User claims.
/// </summary>
public DbSet<IdentityUserClaim<TKey>> UserClaims { get; set; }
public DbSet<TUserClaim> UserClaims { get; set; }
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of User logins.
/// </summary>
public DbSet<IdentityUserLogin<TKey>> UserLogins { get; set; }
public DbSet<TUserLogin> UserLogins { get; set; }
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of User roles.
/// </summary>
public DbSet<IdentityUserRole<TKey>> UserRoles { get; set; }
public DbSet<TUserRole> UserRoles { get; set; }
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of User tokens.
/// </summary>
public DbSet<IdentityUserToken<TKey>> UserTokens { get; set; }
public DbSet<TUserToken> UserTokens { get; set; }
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of roles.
@ -103,7 +137,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// <summary>
/// Gets or sets the <see cref="DbSet{TEntity}"/> of role claims.
/// </summary>
public DbSet<IdentityRoleClaim<TKey>> RoleClaims { get; set; }
public DbSet<TRoleClaim> RoleClaims { get; set; }
/// <summary>
/// Configures the schema needed for the identity framework.
@ -144,31 +178,31 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
b.HasMany(r => r.Claims).WithOne().HasForeignKey(rc => rc.RoleId).IsRequired();
});
builder.Entity<IdentityUserClaim<TKey>>(b =>
builder.Entity<TUserClaim>(b =>
{
b.HasKey(uc => uc.Id);
b.ToTable("AspNetUserClaims");
});
builder.Entity<IdentityRoleClaim<TKey>>(b =>
builder.Entity<TRoleClaim>(b =>
{
b.HasKey(rc => rc.Id);
b.ToTable("AspNetRoleClaims");
});
builder.Entity<IdentityUserRole<TKey>>(b =>
builder.Entity<TUserRole>(b =>
{
b.HasKey(r => new { r.UserId, r.RoleId });
b.ToTable("AspNetUserRoles");
});
builder.Entity<IdentityUserLogin<TKey>>(b =>
builder.Entity<TUserLogin>(b =>
{
b.HasKey(l => new { l.LoginProvider, l.ProviderKey });
b.ToTable("AspNetUserLogins");
});
builder.Entity<IdentityUserToken<TKey>>(b =>
builder.Entity<TUserToken>(b =>
{
b.HasKey(l => new { l.UserId, l.LoginProvider, l.Name });
b.ToTable("AspNetUserTokens");

View File

@ -43,16 +43,9 @@ namespace Microsoft.Extensions.DependencyInjection
{
Type userStoreType;
Type roleStoreType;
if (keyType != null)
{
userStoreType = typeof(UserStore<,,,>).MakeGenericType(userType, roleType, contextType, keyType);
roleStoreType = typeof(RoleStore<,,>).MakeGenericType(roleType, contextType, keyType);
}
else
{
userStoreType = typeof(UserStore<,,>).MakeGenericType(userType, roleType, contextType);
roleStoreType = typeof(RoleStore<,>).MakeGenericType(roleType, contextType);
}
keyType = keyType ?? typeof(string);
userStoreType = typeof(UserStore<,,,>).MakeGenericType(userType, roleType, contextType, keyType);
roleStoreType = typeof(RoleStore<,,>).MakeGenericType(roleType, contextType, keyType);
var services = new ServiceCollection();
services.AddScoped(

View File

@ -39,7 +39,21 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// 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> where TKey : IEquatable<TKey>
public class IdentityRole<TKey> : IdentityRole<TKey, IdentityUserRole<TKey>, IdentityRoleClaim<TKey>>
where TKey : IEquatable<TKey>
{
}
/// <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>
{
/// <summary>
/// Initializes a new instance of <see cref="IdentityRole{TKey}"/>.
@ -58,12 +72,12 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// <summary>
/// Navigation property for the users in this role.
/// </summary>
public virtual ICollection<IdentityUserRole<TKey>> Users { get; } = new List<IdentityUserRole<TKey>>();
public virtual ICollection<TUserRole> Users { get; } = new List<TUserRole>();
/// <summary>
/// Navigation property for claims in this role.
/// </summary>
public virtual ICollection<IdentityRoleClaim<TKey>> Claims { get; } = new List<IdentityRoleClaim<TKey>>();
public virtual ICollection<TRoleClaim> Claims { get; } = new List<TRoleClaim>();
/// <summary>
/// Gets or sets the primary key for this role.

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Security.Claims;
namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
{
@ -30,5 +31,16 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// Gets or sets the claim value for this claim.
/// </summary>
public virtual string ClaimValue { get; set; }
public virtual Claim ToClaim()
{
return new Claim(ClaimType, ClaimValue);
}
public virtual void InitializeFromClaim(Claim other)
{
ClaimType = other?.Type;
ClaimValue = other?.Value;
}
}
}

View File

@ -39,7 +39,18 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// 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> where TKey : IEquatable<TKey>
public class IdentityUser<TKey> : IdentityUser<TKey, IdentityUserClaim<TKey>, IdentityUserRole<TKey>, IdentityUserLogin<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>
public class IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin> where TKey : IEquatable<TKey>
{
/// <summary>
/// Initializes a new instance of <see cref="IdentityUser{TKey}"/>.
@ -140,17 +151,17 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// <summary>
/// Navigation property for the roles this user belongs to.
/// </summary>
public virtual ICollection<IdentityUserRole<TKey>> Roles { get; } = new List<IdentityUserRole<TKey>>();
public virtual ICollection<TUserRole> Roles { get; } = new List<TUserRole>();
/// <summary>
/// Navigation property for the claims this user possesses.
/// </summary>
public virtual ICollection<IdentityUserClaim<TKey>> Claims { get; } = new List<IdentityUserClaim<TKey>>();
public virtual ICollection<TUserClaim> Claims { get; } = new List<TUserClaim>();
/// <summary>
/// Navigation property for this users login accounts.
/// </summary>
public virtual ICollection<IdentityUserLogin<TKey>> Logins { get; } = new List<IdentityUserLogin<TKey>>();
public virtual ICollection<TUserLogin> Logins { get; } = new List<TUserLogin>();
/// <summary>
/// Returns the username for this user.

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Security.Claims;
namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
{
@ -30,5 +31,24 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// Gets or sets the claim value for this claim.
/// </summary>
public virtual string ClaimValue { get; set; }
/// <summary>
/// Converts the entity into a Claim instance.
/// </summary>
/// <returns></returns>
public virtual Claim ToClaim()
{
return new Claim(ClaimType, ClaimValue);
}
/// <summary>
/// Reads the type and value from the Claim.
/// </summary>
/// <param name="claim"></param>
public virtual void InitializeFromClaim(Claim claim)
{
ClaimType = claim.Type;
ClaimValue = claim.Value;
}
}
}

View File

@ -40,12 +40,39 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// <typeparam name="TRole">The type of the class representing a role.</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 RoleStore<TRole, TContext, TKey> :
public class RoleStore<TRole, TContext, TKey> : RoleStore<TRole, TContext, TKey, IdentityUserRole<TKey>, IdentityRoleClaim<TKey>>,
IQueryableRoleStore<TRole>,
IRoleClaimStore<TRole>
where TRole : IdentityRole<TKey>
where TKey : IEquatable<TKey>
where TContext : DbContext
{
public RoleStore(TContext context, IdentityErrorDescriber describer = null) : base(context, describer)
{
}
protected override IdentityRoleClaim<TKey> CreateRoleClaim(TRole role, Claim claim)
{
return new IdentityRoleClaim<TKey> { RoleId = role.Id, ClaimType = claim.Type, ClaimValue = claim.Value };
}
}
/// <summary>
/// Creates a new instance of a persistence store for roles.
/// </summary>
/// <typeparam name="TRole">The type of the class representing a role.</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="TUserRole">The type of the class representing a user role.</typeparam>
/// <typeparam name="TRoleClaim">The type of the class representing a role claim.</typeparam>
public abstract class RoleStore<TRole, TContext, TKey, TUserRole, TRoleClaim> :
IQueryableRoleStore<TRole>,
IRoleClaimStore<TRole>
where TRole : IdentityRole<TKey, TUserRole, TRoleClaim>
where TKey : IEquatable<TKey>
where TContext : DbContext
where TUserRole : IdentityUserRole<TKey>
where TRoleClaim : IdentityRoleClaim<TKey>
{
public RoleStore(TContext context, IdentityErrorDescriber describer = null)
{
@ -358,8 +385,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
throw new ArgumentNullException(nameof(claim));
}
RoleClaims.Add(new IdentityRoleClaim<TKey> { RoleId = role.Id, ClaimType = claim.Type, ClaimValue = claim.Value });
RoleClaims.Add(CreateRoleClaim(role, claim));
return Task.FromResult(false);
}
@ -396,6 +422,14 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
get { return Context.Set<TRole>(); }
}
private DbSet<IdentityRoleClaim<TKey>> RoleClaims { get { return Context.Set<IdentityRoleClaim<TKey>>(); } }
private DbSet<TRoleClaim> RoleClaims { get { return Context.Set<TRoleClaim>(); } }
/// <summary>
/// Creates a entity representing a role claim.
/// </summary>
/// <param name="role"></param>
/// <param name="claim"></param>
/// <returns></returns>
protected abstract TRoleClaim CreateRoleClaim(TRole role, Claim claim);
}
}

View File

@ -14,7 +14,7 @@ using Microsoft.EntityFrameworkCore;
namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
{
/// <summary>
/// Creates a new instance of a persistence store for users, using the default implementation
/// Represents a new instance of a persistence store for users, using the default implementation
/// of <see cref="IdentityUser{TKey}"/> with a string as a primary key.
/// </summary>
public class UserStore : UserStore<IdentityUser<string>>
@ -26,25 +26,78 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// 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 UserStore<TUser> : UserStore<TUser, IdentityRole, DbContext>
public class UserStore<TUser> : UserStore<TUser, IdentityRole, DbContext, string>
where TUser : IdentityUser<string>, new()
{
public UserStore(DbContext context, IdentityErrorDescriber describer = null) : base(context, describer) { }
}
/// <summary>
/// Creates 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 and role types.
/// </summary>
/// <typeparam name="TUser">The type representing a user.</typeparam>
/// <typeparam name="TRole">The type representing a role.</typeparam>
/// <typeparam name="TContext">The type of the data context class used to access the store.</typeparam>
public class UserStore<TUser, TRole, TContext> : UserStore<TUser, TRole, TContext, string>
where TUser : IdentityUser<string>, new()
where TRole : IdentityRole<string>, new()
where TUser : IdentityUser<string>
where TRole : IdentityRole<string>
where TContext : DbContext
{
public UserStore(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="TRole">The type representing a role.</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 UserStore<TUser, TRole, TContext, TKey> : UserStore<TUser, TRole, TContext, TKey, IdentityUserClaim<TKey>, IdentityUserRole<TKey>, IdentityUserLogin<TKey>, IdentityUserToken<TKey>>
where TUser : IdentityUser<TKey>
where TRole : IdentityRole<TKey>
where TContext : DbContext
where TKey : IEquatable<TKey>
{
public UserStore(TContext context, IdentityErrorDescriber describer = null) : base(context, describer) { }
protected override IdentityUserRole<TKey> CreateUserRole(TUser user, TRole role)
{
return new IdentityUserRole<TKey>()
{
UserId = user.Id,
RoleId = role.Id
};
}
protected override IdentityUserClaim<TKey> CreateUserClaim(TUser user, Claim claim)
{
var userClaim = new IdentityUserClaim<TKey> { UserId = user.Id };
userClaim.InitializeFromClaim(claim);
return userClaim;
}
protected override IdentityUserLogin<TKey> CreateUserLogin(TUser user, UserLoginInfo login)
{
return new IdentityUserLogin<TKey>
{
UserId = user.Id,
ProviderKey = login.ProviderKey,
LoginProvider = login.LoginProvider,
ProviderDisplayName = login.ProviderDisplayName
};
}
protected override IdentityUserToken<TKey> CreateUserToken(TUser user, string loginProvider, string name, string value)
{
return new IdentityUserToken<TKey>
{
UserId = user.Id,
LoginProvider = loginProvider,
Name = name,
Value = value
};
}
}
/// <summary>
/// Represents a new instance of a persistence store for the specified user and role types.
@ -53,7 +106,11 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// <typeparam name="TRole">The type representing a role.</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 UserStore<TUser, TRole, TContext, TKey> :
/// <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>
public abstract class UserStore<TUser, TRole, TContext, TKey, TUserClaim, TUserRole, TUserLogin, TUserToken> :
IUserLoginStore<TUser>,
IUserRoleStore<TUser>,
IUserClaimStore<TUser>,
@ -65,12 +122,15 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
IQueryableUserStore<TUser>,
IUserTwoFactorStore<TUser>,
IUserAuthenticationTokenStore<TUser>
where TUser : IdentityUser<TKey>
where TRole : IdentityRole<TKey>
where TUser : IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin>
where TRole : IdentityRole<TKey, TUserRole, IdentityRoleClaim<TKey>>
where TContext : DbContext
where TKey : IEquatable<TKey>
where TUserClaim : IdentityUserClaim<TKey>
where TUserRole : IdentityUserRole<TKey>
where TUserLogin : IdentityUserLogin<TKey>
where TUserToken : IdentityUserToken<TKey>
{
/// <summary>
/// Creates a new instance of <see cref="UserStore"/>.
/// </summary>
@ -98,6 +158,46 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// </summary>
public IdentityErrorDescriber ErrorDescriber { get; set; }
private DbSet<TRole> Roles { get { return Context.Set<TRole>(); } }
private DbSet<TUserClaim> UserClaims { get { return Context.Set<TUserClaim>(); } }
private DbSet<TUserRole> UserRoles { get { return Context.Set<TUserRole>(); } }
private DbSet<TUserLogin> UserLogins { get { return Context.Set<TUserLogin>(); } }
private DbSet<TUserToken> UserTokens { get { return Context.Set<TUserToken>(); } }
/// <summary>
/// Creates a new entity to represent a user role.
/// </summary>
/// <param name="user"></param>
/// <param name="role"></param>
/// <returns></returns>
protected abstract TUserRole CreateUserRole(TUser user, TRole role);
/// <summary>
/// Create a new entity representing a user claim.
/// </summary>
/// <param name="user"></param>
/// <param name="claim"></param>
/// <returns></returns>
protected abstract TUserClaim CreateUserClaim(TUser user, Claim claim);
/// <summary>
/// Create a new entity representing a user login.
/// </summary>
/// <param name="user"></param>
/// <param name="login"></param>
/// <returns></returns>
protected abstract TUserLogin CreateUserLogin(TUser user, UserLoginInfo login);
/// <summary>
/// Create a new entity representing a user token.
/// </summary>
/// <param name="user"></param>
/// <param name="loginProvider"></param>
/// <param name="name"></param>
/// <param name="value"></param>
/// <returns></returns>
protected abstract TUserToken CreateUserToken(TUser user, string loginProvider, string name, string value);
/// <summary>
/// Gets or sets a flag indicating if changes should be persisted after CreateAsync, UpdateAsync and DeleteAsync are called.
/// </summary>
@ -109,7 +209,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
/// <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>
private Task SaveChanges(CancellationToken cancellationToken)
protected Task SaveChanges(CancellationToken cancellationToken)
{
return AutoSaveChanges ? Context.SaveChangesAsync(cancellationToken) : Task.FromResult(0);
}
@ -418,8 +518,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
{
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Resources.RoleNotFound, normalizedRoleName));
}
var ur = new IdentityUserRole<TKey> { UserId = user.Id, RoleId = roleEntity.Id };
UserRoles.Add(ur);
UserRoles.Add(CreateUserRole(user, roleEntity));
}
/// <summary>
@ -520,12 +619,6 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
_disposed = true;
}
private DbSet<TRole> Roles { get { return Context.Set<TRole>(); } }
private DbSet<IdentityUserClaim<TKey>> UserClaims { get { return Context.Set<IdentityUserClaim<TKey>>(); } }
private DbSet<IdentityUserRole<TKey>> UserRoles { get { return Context.Set<IdentityUserRole<TKey>>(); } }
private DbSet<IdentityUserLogin<TKey>> UserLogins { get { return Context.Set<IdentityUserLogin<TKey>>(); } }
private DbSet<IdentityUserToken<TKey>> UserTokens { get { return Context.Set<IdentityUserToken<TKey>>(); } }
/// <summary>
/// Get the claims associated with the specified <paramref name="user"/> as an asynchronous operation.
/// </summary>
@ -540,7 +633,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
throw new ArgumentNullException(nameof(user));
}
return await UserClaims.Where(uc => uc.UserId.Equals(user.Id)).Select(c => new Claim(c.ClaimType, c.ClaimValue)).ToListAsync(cancellationToken);
return await UserClaims.Where(uc => uc.UserId.Equals(user.Id)).Select(c => c.ToClaim()).ToListAsync(cancellationToken);
}
/// <summary>
@ -563,7 +656,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
}
foreach (var claim in claims)
{
UserClaims.Add(new IdentityUserClaim<TKey> { UserId = user.Id, ClaimType = claim.Type, ClaimValue = claim.Value });
UserClaims.Add(CreateUserClaim(user, claim));
}
return Task.FromResult(false);
}
@ -648,14 +741,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
{
throw new ArgumentNullException(nameof(login));
}
var l = new IdentityUserLogin<TKey>
{
UserId = user.Id,
ProviderKey = login.ProviderKey,
LoginProvider = login.LoginProvider,
ProviderDisplayName = login.ProviderDisplayName
};
UserLogins.Add(l);
UserLogins.Add(CreateUserLogin(user, login));
return Task.FromResult(false);
}
@ -676,8 +762,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
{
throw new ArgumentNullException(nameof(user));
}
var userId = user.Id;
var entry = await UserLogins.SingleOrDefaultAsync(l => l.UserId.Equals(userId) && l.LoginProvider == loginProvider && l.ProviderKey == providerKey, cancellationToken);
var entry = await UserLogins.SingleOrDefaultAsync(userLogin => userLogin.UserId.Equals(user.Id) && userLogin.LoginProvider == loginProvider && userLogin.ProviderKey == providerKey, cancellationToken);
if (entry != null)
{
UserLogins.Remove(entry);
@ -1198,7 +1283,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
return new List<TUser>();
}
private Task<IdentityUserToken<TKey>> FindToken(TUser user, string loginProvider, string name, CancellationToken cancellationToken)
private Task<TUserToken> FindToken(TUser user, string loginProvider, string name, CancellationToken cancellationToken)
{
var userId = user.Id;
return UserTokens.SingleOrDefaultAsync(l => l.UserId.Equals(userId) && l.LoginProvider == loginProvider && l.Name == name, cancellationToken);
@ -1218,13 +1303,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore
var token = await FindToken(user, loginProvider, name, cancellationToken);
if (token == null)
{
UserTokens.Add(new IdentityUserToken<TKey>
{
UserId = user.Id,
LoginProvider = loginProvider,
Name = name,
Value = value
});
UserTokens.Add(CreateUserToken(user, loginProvider, name, value));
}
else
{

View File

@ -3,7 +3,6 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test
{
@ -22,7 +21,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test
{ }
}
public class InMemoryContext<TUser, TRole, TKey> : IdentityDbContext<TUser,TRole,TKey>
public class InMemoryContext<TUser, TRole, TKey> : IdentityDbContext<TUser, TRole, TKey>
where TUser : IdentityUser<TKey>
where TRole : IdentityRole<TKey>
where TKey : IEquatable<TKey>
@ -35,4 +34,23 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test
optionsBuilder.UseInMemoryDatabase();
}
}
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>
where TRole : IdentityRole<TKey, TUserRole, TRoleClaim>
where TKey : IEquatable<TKey>
where TUserClaim : IdentityUserClaim<TKey>
where TUserRole : IdentityUserRole<TKey>
where TUserLogin : IdentityUserLogin<TKey>
where TRoleClaim : IdentityRoleClaim<TKey>
where TUserToken : IdentityUserToken<TKey>
{
public InMemoryContext(DbContextOptions options) : base(options)
{ }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseInMemoryDatabase();
}
}
}

View File

@ -5,7 +5,6 @@ using System;
using System.Linq.Expressions;
using Microsoft.AspNetCore.Identity.Test;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test

View File

@ -0,0 +1,320 @@
// 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.Linq.Expressions;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity.Test;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test
{
public class InMemoryEFUserStoreTestWithGenerics : UserManagerTestBase<IdentityUserWithGenerics, MyIdentityRole, string>, IDisposable
{
private readonly InMemoryContextWithGenerics _context;
private UserStoreWithGenerics _store;
public InMemoryEFUserStoreTestWithGenerics()
{
var services = new ServiceCollection();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddDbContext<InMemoryContextWithGenerics>(options => options.UseInMemoryDatabase());
_context = services.BuildServiceProvider().GetRequiredService<InMemoryContextWithGenerics>();
}
protected override object CreateTestContext()
{
return _context;
}
protected override void AddUserStore(IServiceCollection services, object context = null)
{
_store = new UserStoreWithGenerics((InMemoryContextWithGenerics)context, "TestContext");
services.AddSingleton<IUserStore<IdentityUserWithGenerics>>(_store);
}
protected override void AddRoleStore(IServiceCollection services, object context = null)
{
services.AddSingleton<IRoleStore<MyIdentityRole>>(new RoleStoreWithGenerics((InMemoryContextWithGenerics)context, "TestContext"));
}
protected override IdentityUserWithGenerics CreateTestUser(string namePrefix = "", string email = "", string phoneNumber = "",
bool lockoutEnabled = false, DateTimeOffset? lockoutEnd = default(DateTimeOffset?), bool useNamePrefixAsUserName = false)
{
return new IdentityUserWithGenerics
{
UserName = useNamePrefixAsUserName ? namePrefix : string.Format("{0}{1}", namePrefix, Guid.NewGuid()),
Email = email,
PhoneNumber = phoneNumber,
LockoutEnabled = lockoutEnabled,
LockoutEnd = lockoutEnd
};
}
protected override MyIdentityRole CreateTestRole(string roleNamePrefix = "", bool useRoleNamePrefixAsRoleName = false)
{
var roleName = useRoleNamePrefixAsRoleName ? roleNamePrefix : string.Format("{0}{1}", roleNamePrefix, Guid.NewGuid());
return new MyIdentityRole(roleName);
}
protected override void SetUserPasswordHash(IdentityUserWithGenerics user, string hashedPassword)
{
user.PasswordHash = hashedPassword;
}
protected override Expression<Func<IdentityUserWithGenerics, bool>> UserNameEqualsPredicate(string userName) => u => u.UserName == userName;
protected override Expression<Func<MyIdentityRole, bool>> RoleNameEqualsPredicate(string roleName) => r => r.Name == roleName;
protected override Expression<Func<IdentityUserWithGenerics, bool>> UserNameStartsWithPredicate(string userName) => u => u.UserName.StartsWith(userName);
protected override Expression<Func<MyIdentityRole, bool>> RoleNameStartsWithPredicate(string roleName) => r => r.Name.StartsWith(roleName);
[Fact]
public async Task CanAddRemoveUserClaimWithIssuer()
{
if (ShouldSkipDbTests())
{
return;
}
var manager = CreateManager();
var user = CreateTestUser();
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
Claim[] claims = { new Claim("c1", "v1", null, "i1"), new Claim("c2", "v2", null, "i2"), new Claim("c2", "v3", null, "i3") };
foreach (Claim c in claims)
{
IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user, c));
}
var userId = await manager.GetUserIdAsync(user);
var userClaims = await manager.GetClaimsAsync(user);
Assert.Equal(3, userClaims.Count);
Assert.Equal(3, userClaims.Intersect(claims, ClaimEqualityComparer.Default).Count());
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(user, claims[0]));
userClaims = await manager.GetClaimsAsync(user);
Assert.Equal(2, userClaims.Count);
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(user, claims[1]));
userClaims = await manager.GetClaimsAsync(user);
Assert.Equal(1, userClaims.Count);
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(user, claims[2]));
userClaims = await manager.GetClaimsAsync(user);
Assert.Equal(0, userClaims.Count);
}
[Fact]
public async Task RemoveClaimWithIssuerOnlyAffectsUser()
{
if (ShouldSkipDbTests())
{
return;
}
var manager = CreateManager();
var user = CreateTestUser();
var user2 = CreateTestUser();
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user2));
Claim[] claims = { new Claim("c", "v", null, "i1"), new Claim("c2", "v2", null, "i2"), new Claim("c2", "v3", null, "i3") };
foreach (Claim c in claims)
{
IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user, c));
IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user2, c));
}
var userClaims = await manager.GetClaimsAsync(user);
Assert.Equal(3, userClaims.Count);
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(user, claims[0]));
userClaims = await manager.GetClaimsAsync(user);
Assert.Equal(2, userClaims.Count);
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(user, claims[1]));
userClaims = await manager.GetClaimsAsync(user);
Assert.Equal(1, userClaims.Count);
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(user, claims[2]));
userClaims = await manager.GetClaimsAsync(user);
Assert.Equal(0, userClaims.Count);
var userClaims2 = await manager.GetClaimsAsync(user2);
Assert.Equal(3, userClaims2.Count);
}
[Fact]
public async Task CanReplaceUserClaimWithIssuer()
{
if (ShouldSkipDbTests())
{
return;
}
var manager = CreateManager();
var user = CreateTestUser();
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user, new Claim("c", "a", "i")));
var userClaims = await manager.GetClaimsAsync(user);
Assert.Equal(1, userClaims.Count);
Claim claim = new Claim("c", "b", "i");
Claim oldClaim = userClaims.FirstOrDefault();
IdentityResultAssert.IsSuccess(await manager.ReplaceClaimAsync(user, oldClaim, claim));
var newUserClaims = await manager.GetClaimsAsync(user);
Assert.Equal(1, newUserClaims.Count);
Claim newClaim = newUserClaims.FirstOrDefault();
Assert.Equal(claim.Type, newClaim.Type);
Assert.Equal(claim.Value, newClaim.Value);
Assert.Equal(claim.Issuer, newClaim.Issuer);
}
public void Dispose()
{
}
}
public class ClaimEqualityComparer : IEqualityComparer<Claim>
{
public static IEqualityComparer<Claim> Default = new ClaimEqualityComparer();
public bool Equals(Claim x, Claim y)
{
return x.Value == y.Value && x.Type == y.Type && x.Issuer == y.Issuer;
}
public int GetHashCode(Claim obj)
{
return 1;
}
}
#region Generic Type defintions
public class IdentityUserWithGenerics : IdentityUser<string, IdentityUserClaimWithIssuer, IdentityUserRoleWithDate, IdentityUserLoginWithContext>
{
public IdentityUserWithGenerics()
{
Id = Guid.NewGuid().ToString();
}
}
public class UserStoreWithGenerics : UserStore<IdentityUserWithGenerics, MyIdentityRole, InMemoryContextWithGenerics, string, IdentityUserClaimWithIssuer, IdentityUserRoleWithDate, IdentityUserLoginWithContext, IdentityUserTokenWithStuff>
{
public string LoginContext { get; set; }
public UserStoreWithGenerics(InMemoryContextWithGenerics context, string loginContext) : base(context)
{
LoginContext = loginContext;
}
protected override IdentityUserRoleWithDate CreateUserRole(IdentityUserWithGenerics user, MyIdentityRole role)
{
return new IdentityUserRoleWithDate()
{
RoleId = role.Id,
UserId = user.Id,
Created = DateTime.UtcNow
};
}
protected override IdentityUserClaimWithIssuer CreateUserClaim(IdentityUserWithGenerics user, Claim claim)
{
return new IdentityUserClaimWithIssuer { UserId = user.Id, ClaimType = claim.Type, ClaimValue = claim.Value, Issuer = claim.Issuer };
}
protected override IdentityUserLoginWithContext CreateUserLogin(IdentityUserWithGenerics user, UserLoginInfo login)
{
return new IdentityUserLoginWithContext
{
UserId = user.Id,
ProviderKey = login.ProviderKey,
LoginProvider = login.LoginProvider,
ProviderDisplayName = login.ProviderDisplayName,
Context = LoginContext
};
}
protected override IdentityUserTokenWithStuff CreateUserToken(IdentityUserWithGenerics user, string loginProvider, string name, string value)
{
return new IdentityUserTokenWithStuff
{
UserId = user.Id,
LoginProvider = loginProvider,
Name = name,
Value = value,
Stuff = "stuff"
};
}
}
public class RoleStoreWithGenerics : RoleStore<MyIdentityRole, InMemoryContextWithGenerics, string, IdentityUserRoleWithDate, IdentityRoleClaim<string>>
{
private string _loginContext;
public RoleStoreWithGenerics(InMemoryContextWithGenerics context, string loginContext) : base(context)
{
_loginContext = loginContext;
}
protected override IdentityRoleClaim<string> CreateRoleClaim(MyIdentityRole role, Claim claim)
{
return new IdentityRoleClaim<string> { RoleId = role.Id, ClaimType = claim.Type, ClaimValue = claim.Value };
}
}
public class IdentityUserClaimWithIssuer : IdentityUserClaim<string>
{
public string Issuer { get; set; }
public override Claim ToClaim()
{
return new Claim(ClaimType, ClaimValue, null, Issuer);
}
public override void InitializeFromClaim(Claim other)
{
ClaimValue = other.Value;
ClaimType = other.Type;
Issuer = other.Issuer;
}
}
public class IdentityUserRoleWithDate : IdentityUserRole<string>
{
public DateTime Created { get; set; }
}
public class MyIdentityRole : IdentityRole<string, IdentityUserRoleWithDate, IdentityRoleClaim<string>>
{
public MyIdentityRole() : base()
{
Id = Guid.NewGuid().ToString();
}
public MyIdentityRole(string roleName) : this()
{
Name = roleName;
}
}
public class IdentityUserTokenWithStuff : IdentityUserToken<string>
{
public string Stuff { get; set; }
}
public class IdentityUserLoginWithContext : IdentityUserLogin<string>
{
public string Context { get; set; }
}
public class InMemoryContextWithGenerics : InMemoryContext<IdentityUserWithGenerics, MyIdentityRole, string, IdentityUserClaimWithIssuer, IdentityUserRoleWithDate, IdentityUserLoginWithContext, IdentityRoleClaim<string>, IdentityUserTokenWithStuff>
{
public InMemoryContextWithGenerics(DbContextOptions options) : base(options)
{ }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseInMemoryDatabase();
}
}
#endregion
}

View File

@ -9,7 +9,6 @@ using Microsoft.AspNetCore.Identity.Test;
using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.AspNetCore.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using Xunit;

View File

@ -0,0 +1,316 @@
// 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.Linq.Expressions;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity.Test;
using Microsoft.AspNetCore.Testing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test
{
public class UserStoreWithGenericsTest : UserManagerTestBase<IdentityUserWithGenerics, MyIdentityRole, string>, IClassFixture<ScratchDatabaseFixture>
{
private readonly ScratchDatabaseFixture _fixture;
public UserStoreWithGenericsTest(ScratchDatabaseFixture fixture)
{
_fixture = fixture;
}
public ContextWithGenerics CreateContext()
{
var db = DbUtil.Create<ContextWithGenerics>(_fixture.ConnectionString);
db.Database.EnsureCreated();
return db;
}
protected override object CreateTestContext()
{
return CreateContext();
}
protected override bool ShouldSkipDbTests()
{
return TestPlatformHelper.IsMono || !TestPlatformHelper.IsWindows;
}
protected override void AddUserStore(IServiceCollection services, object context = null)
{
services.AddSingleton<IUserStore<IdentityUserWithGenerics>>(new UserStoreWithGenerics((ContextWithGenerics)context, "TestContext"));
}
protected override void AddRoleStore(IServiceCollection services, object context = null)
{
services.AddSingleton<IRoleStore<MyIdentityRole>>(new RoleStoreWithGenerics((ContextWithGenerics)context, "TestContext"));
}
protected override IdentityUserWithGenerics CreateTestUser(string namePrefix = "", string email = "", string phoneNumber = "",
bool lockoutEnabled = false, DateTimeOffset? lockoutEnd = default(DateTimeOffset?), bool useNamePrefixAsUserName = false)
{
return new IdentityUserWithGenerics
{
UserName = useNamePrefixAsUserName ? namePrefix : string.Format("{0}{1}", namePrefix, Guid.NewGuid()),
Email = email,
PhoneNumber = phoneNumber,
LockoutEnabled = lockoutEnabled,
LockoutEnd = lockoutEnd
};
}
protected override MyIdentityRole CreateTestRole(string roleNamePrefix = "", bool useRoleNamePrefixAsRoleName = false)
{
var roleName = useRoleNamePrefixAsRoleName ? roleNamePrefix : string.Format("{0}{1}", roleNamePrefix, Guid.NewGuid());
return new MyIdentityRole(roleName);
}
protected override void SetUserPasswordHash(IdentityUserWithGenerics user, string hashedPassword)
{
user.PasswordHash = hashedPassword;
}
protected override Expression<Func<IdentityUserWithGenerics, bool>> UserNameEqualsPredicate(string userName) => u => u.UserName == userName;
protected override Expression<Func<MyIdentityRole, bool>> RoleNameEqualsPredicate(string roleName) => r => r.Name == roleName;
protected override Expression<Func<IdentityUserWithGenerics, bool>> UserNameStartsWithPredicate(string userName) => u => u.UserName.StartsWith(userName);
protected override Expression<Func<MyIdentityRole, bool>> RoleNameStartsWithPredicate(string roleName) => r => r.Name.StartsWith(roleName);
[Fact]
public async Task CanAddRemoveUserClaimWithIssuer()
{
if (ShouldSkipDbTests())
{
return;
}
var manager = CreateManager();
var user = CreateTestUser();
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
Claim[] claims = { new Claim("c1", "v1", null, "i1"), new Claim("c2", "v2", null, "i2"), new Claim("c2", "v3", null, "i3") };
foreach (Claim c in claims)
{
IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user, c));
}
var userId = await manager.GetUserIdAsync(user);
var userClaims = await manager.GetClaimsAsync(user);
Assert.Equal(3, userClaims.Count);
Assert.Equal(3, userClaims.Intersect(claims, ClaimEqualityComparer.Default).Count());
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(user, claims[0]));
userClaims = await manager.GetClaimsAsync(user);
Assert.Equal(2, userClaims.Count);
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(user, claims[1]));
userClaims = await manager.GetClaimsAsync(user);
Assert.Equal(1, userClaims.Count);
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(user, claims[2]));
userClaims = await manager.GetClaimsAsync(user);
Assert.Equal(0, userClaims.Count);
}
[Fact]
public async Task RemoveClaimWithIssuerOnlyAffectsUser()
{
if (ShouldSkipDbTests())
{
return;
}
var manager = CreateManager();
var user = CreateTestUser();
var user2 = CreateTestUser();
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user2));
Claim[] claims = { new Claim("c", "v", null, "i1"), new Claim("c2", "v2", null, "i2"), new Claim("c2", "v3", null, "i3") };
foreach (Claim c in claims)
{
IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user, c));
IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user2, c));
}
var userClaims = await manager.GetClaimsAsync(user);
Assert.Equal(3, userClaims.Count);
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(user, claims[0]));
userClaims = await manager.GetClaimsAsync(user);
Assert.Equal(2, userClaims.Count);
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(user, claims[1]));
userClaims = await manager.GetClaimsAsync(user);
Assert.Equal(1, userClaims.Count);
IdentityResultAssert.IsSuccess(await manager.RemoveClaimAsync(user, claims[2]));
userClaims = await manager.GetClaimsAsync(user);
Assert.Equal(0, userClaims.Count);
var userClaims2 = await manager.GetClaimsAsync(user2);
Assert.Equal(3, userClaims2.Count);
}
[Fact]
public async Task CanReplaceUserClaimWithIssuer()
{
if (ShouldSkipDbTests())
{
return;
}
var manager = CreateManager();
var user = CreateTestUser();
IdentityResultAssert.IsSuccess(await manager.CreateAsync(user));
IdentityResultAssert.IsSuccess(await manager.AddClaimAsync(user, new Claim("c", "a", "i")));
var userClaims = await manager.GetClaimsAsync(user);
Assert.Equal(1, userClaims.Count);
Claim claim = new Claim("c", "b", "i");
Claim oldClaim = userClaims.FirstOrDefault();
IdentityResultAssert.IsSuccess(await manager.ReplaceClaimAsync(user, oldClaim, claim));
var newUserClaims = await manager.GetClaimsAsync(user);
Assert.Equal(1, newUserClaims.Count);
Claim newClaim = newUserClaims.FirstOrDefault();
Assert.Equal(claim.Type, newClaim.Type);
Assert.Equal(claim.Value, newClaim.Value);
Assert.Equal(claim.Issuer, newClaim.Issuer);
}
}
public class ClaimEqualityComparer : IEqualityComparer<Claim>
{
public static IEqualityComparer<Claim> Default = new ClaimEqualityComparer();
public bool Equals(Claim x, Claim y)
{
return x.Value == y.Value && x.Type == y.Type && x.Issuer == y.Issuer;
}
public int GetHashCode(Claim obj)
{
return 1;
}
}
#region Generic Type defintions
public class IdentityUserWithGenerics : IdentityUser<string, IdentityUserClaimWithIssuer, IdentityUserRoleWithDate, IdentityUserLoginWithContext>
{
public IdentityUserWithGenerics()
{
Id = Guid.NewGuid().ToString();
}
}
public class UserStoreWithGenerics : UserStore<IdentityUserWithGenerics, MyIdentityRole, ContextWithGenerics, string, IdentityUserClaimWithIssuer, IdentityUserRoleWithDate, IdentityUserLoginWithContext, IdentityUserTokenWithStuff>
{
public string LoginContext { get; set; }
public UserStoreWithGenerics(ContextWithGenerics context, string loginContext) : base(context)
{
LoginContext = loginContext;
}
protected override IdentityUserRoleWithDate CreateUserRole(IdentityUserWithGenerics user, MyIdentityRole role)
{
return new IdentityUserRoleWithDate()
{
RoleId = role.Id,
UserId = user.Id,
Created = DateTime.UtcNow
};
}
protected override IdentityUserClaimWithIssuer CreateUserClaim(IdentityUserWithGenerics user, Claim claim)
{
return new IdentityUserClaimWithIssuer { UserId = user.Id, ClaimType = claim.Type, ClaimValue = claim.Value, Issuer = claim.Issuer };
}
protected override IdentityUserLoginWithContext CreateUserLogin(IdentityUserWithGenerics user, UserLoginInfo login)
{
return new IdentityUserLoginWithContext
{
UserId = user.Id,
ProviderKey = login.ProviderKey,
LoginProvider = login.LoginProvider,
ProviderDisplayName = login.ProviderDisplayName,
Context = LoginContext
};
}
protected override IdentityUserTokenWithStuff CreateUserToken(IdentityUserWithGenerics user, string loginProvider, string name, string value)
{
return new IdentityUserTokenWithStuff
{
UserId = user.Id,
LoginProvider = loginProvider,
Name = name,
Value = value,
Stuff = "stuff"
};
}
}
public class RoleStoreWithGenerics : RoleStore<MyIdentityRole, ContextWithGenerics, string, IdentityUserRoleWithDate, IdentityRoleClaim<string>>
{
private string _loginContext;
public RoleStoreWithGenerics(ContextWithGenerics context, string loginContext) : base(context)
{
_loginContext = loginContext;
}
protected override IdentityRoleClaim<string> CreateRoleClaim(MyIdentityRole role, Claim claim)
{
return new IdentityRoleClaim<string> { RoleId = role.Id, ClaimType = claim.Type, ClaimValue = claim.Value };
}
}
public class IdentityUserClaimWithIssuer : IdentityUserClaim<string>
{
public string Issuer { get; set; }
public override Claim ToClaim()
{
return new Claim(ClaimType, ClaimValue, null, Issuer);
}
public override void InitializeFromClaim(Claim other)
{
ClaimValue = other.Value;
ClaimType = other.Type;
Issuer = other.Issuer;
}
}
public class IdentityUserRoleWithDate : IdentityUserRole<string>
{
public DateTime Created { get; set; }
}
public class MyIdentityRole : IdentityRole<string, IdentityUserRoleWithDate, IdentityRoleClaim<string>>
{
public MyIdentityRole() : base()
{
Id = Guid.NewGuid().ToString();
}
public MyIdentityRole(string roleName) : this()
{
Name = roleName;
}
}
public class IdentityUserTokenWithStuff : IdentityUserToken<string>
{
public string Stuff { get; set; }
}
public class IdentityUserLoginWithContext : IdentityUserLogin<string>
{
public string Context { get; set; }
}
public class ContextWithGenerics : IdentityDbContext<IdentityUserWithGenerics, MyIdentityRole, string, IdentityUserClaimWithIssuer, IdentityUserRoleWithDate, IdentityUserLoginWithContext, IdentityRoleClaim<string>, IdentityUserTokenWithStuff>
{
public ContextWithGenerics(DbContextOptions options) : base(options) { }
}
#endregion
}