Restore support for EF User store generics
This commit is contained in:
parent
6b6b21a5bf
commit
104f216191
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
Loading…
Reference in New Issue