Skip to content

Commit f555a26

Browse files
committed
Make roles optional in Extensions.Identity
1 parent f91e3ff commit f555a26

File tree

50 files changed

+4709
-3551
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+4709
-3551
lines changed

IdentityCore.sln

Lines changed: 224 additions & 0 deletions
Large diffs are not rendered by default.

build/repo.props

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<Project>
2+
<ItemGroup>
3+
<ExcludeSolutions Include="$(RepositoryRoot)IdentityCore.sln" />
4+
</ItemGroup>
5+
</Project>

src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityDbContext.cs

Lines changed: 107 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ protected IdentityDbContext() { }
2727
/// Base class for the Entity Framework database context used for identity.
2828
/// </summary>
2929
/// <typeparam name="TUser">The type of the user objects.</typeparam>
30-
public class IdentityDbContext<TUser> : IdentityDbContext<TUser, IdentityRole, string> where TUser : IdentityUser
30+
public class IdentityDbContext<TUser> : IdentityDbContext<TUser, string> where TUser : IdentityUser
3131
{
3232
/// <summary>
3333
/// Initializes a new instance of <see cref="IdentityDbContext"/>.
@@ -41,6 +41,27 @@ public IdentityDbContext(DbContextOptions options) : base(options) { }
4141
protected IdentityDbContext() { }
4242
}
4343

44+
/// <summary>
45+
/// Base class for the Entity Framework database context used for identity.
46+
/// </summary>
47+
/// <typeparam name="TUser">The type of user objects.</typeparam>
48+
/// <typeparam name="TKey">The type of the primary key for users and roles.</typeparam>
49+
public class IdentityDbContext<TUser, TKey> : IdentityDbContext<TUser, TKey, IdentityUserClaim<TKey>, IdentityUserLogin<TKey>, IdentityUserToken<TKey>>
50+
where TUser : IdentityUser<TKey>
51+
where TKey : IEquatable<TKey>
52+
{
53+
/// <summary>
54+
/// Initializes a new instance of the db context.
55+
/// </summary>
56+
/// <param name="options">The options to be used by a <see cref="DbContext"/>.</param>
57+
public IdentityDbContext(DbContextOptions options) : base(options) { }
58+
59+
/// <summary>
60+
/// Initializes a new instance of the class.
61+
/// </summary>
62+
protected IdentityDbContext() { }
63+
}
64+
4465
/// <summary>
4566
/// Base class for the Entity Framework database context used for identity.
4667
/// </summary>
@@ -68,21 +89,15 @@ protected IdentityDbContext() { }
6889
/// Base class for the Entity Framework database context used for identity.
6990
/// </summary>
7091
/// <typeparam name="TUser">The type of user objects.</typeparam>
71-
/// <typeparam name="TRole">The type of role objects.</typeparam>
7292
/// <typeparam name="TKey">The type of the primary key for users and roles.</typeparam>
7393
/// <typeparam name="TUserClaim">The type of the user claim object.</typeparam>
74-
/// <typeparam name="TUserRole">The type of the user role object.</typeparam>
7594
/// <typeparam name="TUserLogin">The type of the user login object.</typeparam>
76-
/// <typeparam name="TRoleClaim">The type of the role claim object.</typeparam>
7795
/// <typeparam name="TUserToken">The type of the user token object.</typeparam>
78-
public abstract class IdentityDbContext<TUser, TRole, TKey, TUserClaim, TUserRole, TUserLogin, TRoleClaim, TUserToken> : DbContext
79-
where TUser : IdentityUser<TKey, TUserClaim, TUserRole, TUserLogin, TUserToken>
80-
where TRole : IdentityRole<TKey, TUserRole, TRoleClaim>
96+
public abstract class IdentityDbContext<TUser, TKey, TUserClaim, TUserLogin, TUserToken> : DbContext
97+
where TUser : IdentityUser<TKey>
8198
where TKey : IEquatable<TKey>
8299
where TUserClaim : IdentityUserClaim<TKey>
83-
where TUserRole : IdentityUserRole<TKey>
84100
where TUserLogin : IdentityUserLogin<TKey>
85-
where TRoleClaim : IdentityRoleClaim<TKey>
86101
where TUserToken : IdentityUserToken<TKey>
87102
{
88103
/// <summary>
@@ -111,26 +126,11 @@ protected IdentityDbContext() { }
111126
/// </summary>
112127
public DbSet<TUserLogin> UserLogins { get; set; }
113128

114-
/// <summary>
115-
/// Gets or sets the <see cref="DbSet{TEntity}"/> of User roles.
116-
/// </summary>
117-
public DbSet<TUserRole> UserRoles { get; set; }
118-
119129
/// <summary>
120130
/// Gets or sets the <see cref="DbSet{TEntity}"/> of User tokens.
121131
/// </summary>
122132
public DbSet<TUserToken> UserTokens { get; set; }
123133

124-
/// <summary>
125-
/// Gets or sets the <see cref="DbSet{TEntity}"/> of roles.
126-
/// </summary>
127-
public DbSet<TRole> Roles { get; set; }
128-
129-
/// <summary>
130-
/// Gets or sets the <see cref="DbSet{TEntity}"/> of role claims.
131-
/// </summary>
132-
public DbSet<TRoleClaim> RoleClaims { get; set; }
133-
134134
/// <summary>
135135
/// Configures the schema needed for the identity framework.
136136
/// </summary>
@@ -155,10 +155,90 @@ protected override void OnModelCreating(ModelBuilder builder)
155155
// Replace with b.HasMany<IdentityUserClaim>().
156156
b.HasMany<TUserClaim>().WithOne().HasForeignKey(uc => uc.UserId).IsRequired();
157157
b.HasMany<TUserLogin>().WithOne().HasForeignKey(ul => ul.UserId).IsRequired();
158-
b.HasMany<TUserRole>().WithOne().HasForeignKey(ur => ur.UserId).IsRequired();
159158
b.HasMany<TUserToken>().WithOne().HasForeignKey(ut => ut.UserId).IsRequired();
160159
});
161160

161+
builder.Entity<TUserClaim>(b =>
162+
{
163+
b.HasKey(uc => uc.Id);
164+
b.ToTable("AspNetUserClaims");
165+
});
166+
167+
builder.Entity<TUserLogin>(b =>
168+
{
169+
b.HasKey(l => new { l.LoginProvider, l.ProviderKey });
170+
b.ToTable("AspNetUserLogins");
171+
});
172+
173+
builder.Entity<TUserToken>(b =>
174+
{
175+
b.HasKey(l => new { l.UserId, l.LoginProvider, l.Name });
176+
b.ToTable("AspNetUserTokens");
177+
});
178+
}
179+
}
180+
181+
/// <summary>
182+
/// Base class for the Entity Framework database context used for identity.
183+
/// </summary>
184+
/// <typeparam name="TUser">The type of user objects.</typeparam>
185+
/// <typeparam name="TRole">The type of role objects.</typeparam>
186+
/// <typeparam name="TKey">The type of the primary key for users and roles.</typeparam>
187+
/// <typeparam name="TUserClaim">The type of the user claim object.</typeparam>
188+
/// <typeparam name="TUserRole">The type of the user role object.</typeparam>
189+
/// <typeparam name="TUserLogin">The type of the user login object.</typeparam>
190+
/// <typeparam name="TRoleClaim">The type of the role claim object.</typeparam>
191+
/// <typeparam name="TUserToken">The type of the user token object.</typeparam>
192+
public abstract class IdentityDbContext<TUser, TRole, TKey, TUserClaim, TUserRole, TUserLogin, TRoleClaim, TUserToken> : IdentityDbContext<TUser, TKey, TUserClaim, TUserLogin, TUserToken>
193+
where TUser : IdentityUser<TKey>
194+
where TRole : IdentityRole<TKey>
195+
where TKey : IEquatable<TKey>
196+
where TUserClaim : IdentityUserClaim<TKey>
197+
where TUserRole : IdentityUserRole<TKey>
198+
where TUserLogin : IdentityUserLogin<TKey>
199+
where TRoleClaim : IdentityRoleClaim<TKey>
200+
where TUserToken : IdentityUserToken<TKey>
201+
{
202+
/// <summary>
203+
/// Initializes a new instance of the class.
204+
/// </summary>
205+
/// <param name="options">The options to be used by a <see cref="DbContext"/>.</param>
206+
public IdentityDbContext(DbContextOptions options) : base(options) { }
207+
208+
/// <summary>
209+
/// Initializes a new instance of the class.
210+
/// </summary>
211+
protected IdentityDbContext() { }
212+
213+
/// <summary>
214+
/// Gets or sets the <see cref="DbSet{TEntity}"/> of User roles.
215+
/// </summary>
216+
public DbSet<TUserRole> UserRoles { get; set; }
217+
218+
/// <summary>
219+
/// Gets or sets the <see cref="DbSet{TEntity}"/> of roles.
220+
/// </summary>
221+
public DbSet<TRole> Roles { get; set; }
222+
223+
/// <summary>
224+
/// Gets or sets the <see cref="DbSet{TEntity}"/> of role claims.
225+
/// </summary>
226+
public DbSet<TRoleClaim> RoleClaims { get; set; }
227+
228+
/// <summary>
229+
/// Configures the schema needed for the identity framework.
230+
/// </summary>
231+
/// <param name="builder">
232+
/// The builder being used to construct the model for this context.
233+
/// </param>
234+
protected override void OnModelCreating(ModelBuilder builder)
235+
{
236+
base.OnModelCreating(builder);
237+
builder.Entity<TUser>(b =>
238+
{
239+
b.HasMany<TUserRole>().WithOne().HasForeignKey(ur => ur.UserId).IsRequired();
240+
});
241+
162242
builder.Entity<TRole>(b =>
163243
{
164244
b.HasKey(r => r.Id);
@@ -173,35 +253,17 @@ protected override void OnModelCreating(ModelBuilder builder)
173253
b.HasMany<TRoleClaim>().WithOne().HasForeignKey(rc => rc.RoleId).IsRequired();
174254
});
175255

176-
builder.Entity<TUserClaim>(b =>
177-
{
178-
b.HasKey(uc => uc.Id);
179-
b.ToTable("AspNetUserClaims");
180-
});
181-
182-
builder.Entity<TRoleClaim>(b =>
256+
builder.Entity<TRoleClaim>(b =>
183257
{
184258
b.HasKey(rc => rc.Id);
185259
b.ToTable("AspNetRoleClaims");
186260
});
187261

188-
builder.Entity<TUserRole>(b =>
262+
builder.Entity<TUserRole>(b =>
189263
{
190264
b.HasKey(r => new { r.UserId, r.RoleId });
191265
b.ToTable("AspNetUserRoles");
192266
});
193-
194-
builder.Entity<TUserLogin>(b =>
195-
{
196-
b.HasKey(l => new { l.LoginProvider, l.ProviderKey });
197-
b.ToTable("AspNetUserLogins");
198-
});
199-
200-
builder.Entity<TUserToken>(b =>
201-
{
202-
b.HasKey(l => new { l.UserId, l.LoginProvider, l.Name });
203-
b.ToTable("AspNetUserTokens");
204-
});
205267
}
206268
}
207269
}

src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityEntityFrameworkBuilderExtensions.cs

Lines changed: 55 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,32 +30,68 @@ public static IdentityBuilder AddEntityFrameworkStores<TContext>(this IdentityBu
3030

3131
private static void AddStores(IServiceCollection services, Type userType, Type roleType, Type contextType)
3232
{
33-
var identityUserType = FindGenericBaseType(userType, typeof(IdentityUser<,,,,>));
33+
var identityUserType = FindGenericBaseType(userType, typeof(IdentityUser<>));
3434
if (identityUserType == null)
3535
{
3636
throw new InvalidOperationException(Resources.NotIdentityUser);
3737
}
38-
var identityRoleType = FindGenericBaseType(roleType, typeof(IdentityRole<,,>));
39-
if (identityRoleType == null)
38+
39+
var keyType = identityUserType.GenericTypeArguments[0];
40+
41+
if (roleType != null)
4042
{
41-
throw new InvalidOperationException(Resources.NotIdentityRole);
43+
var identityRoleType = FindGenericBaseType(roleType, typeof(IdentityRole<>));
44+
if (identityRoleType == null)
45+
{
46+
throw new InvalidOperationException(Resources.NotIdentityRole);
47+
}
48+
49+
Type userStoreType = null;
50+
Type roleStoreType = null;
51+
var identityContext = FindGenericBaseType(contextType, typeof(IdentityDbContext<,,,,,,,>));
52+
if (identityContext == null)
53+
{
54+
// If its a custom DbContext, we can only add the default POCOs
55+
userStoreType = typeof(UserStore<,,,>).MakeGenericType(userType, roleType, contextType, keyType);
56+
roleStoreType = typeof(RoleStore<,,>).MakeGenericType(roleType, contextType, keyType);
57+
}
58+
else
59+
{
60+
userStoreType = typeof(UserStore<,,,,,,,,>).MakeGenericType(userType, roleType, contextType,
61+
identityContext.GenericTypeArguments[2],
62+
identityContext.GenericTypeArguments[3],
63+
identityContext.GenericTypeArguments[4],
64+
identityContext.GenericTypeArguments[5],
65+
identityContext.GenericTypeArguments[7],
66+
identityContext.GenericTypeArguments[6]);
67+
roleStoreType = typeof(RoleStore<,,,,>).MakeGenericType(roleType, contextType,
68+
identityContext.GenericTypeArguments[2],
69+
identityContext.GenericTypeArguments[4],
70+
identityContext.GenericTypeArguments[6]);
71+
}
72+
services.TryAddScoped(typeof(IUserStore<>).MakeGenericType(userType), userStoreType);
73+
services.TryAddScoped(typeof(IRoleStore<>).MakeGenericType(roleType), roleStoreType);
74+
}
75+
else
76+
{ // No Roles
77+
Type userStoreType = null;
78+
var identityContext = FindGenericBaseType(contextType, typeof(IdentityDbContext<,,,,>));
79+
if (identityContext == null)
80+
{
81+
// If its a custom DbContext, we can only add the default POCOs
82+
userStoreType = typeof(UserStore<,,,>).MakeGenericType(userType, roleType, contextType, keyType);
83+
}
84+
else
85+
{
86+
userStoreType = typeof(UserOnlyStore<,,,,,>).MakeGenericType(userType, roleType, contextType,
87+
identityContext.GenericTypeArguments[1],
88+
identityContext.GenericTypeArguments[2],
89+
identityContext.GenericTypeArguments[3],
90+
identityContext.GenericTypeArguments[4]);
91+
}
92+
services.TryAddScoped(typeof(IUserStore<>).MakeGenericType(userType), userStoreType);
4293
}
4394

44-
services.TryAddScoped(
45-
typeof(IUserStore<>).MakeGenericType(userType),
46-
typeof(UserStore<,,,,,,,,>).MakeGenericType(userType, roleType, contextType,
47-
identityUserType.GenericTypeArguments[0],
48-
identityUserType.GenericTypeArguments[1],
49-
identityUserType.GenericTypeArguments[2],
50-
identityUserType.GenericTypeArguments[3],
51-
identityUserType.GenericTypeArguments[4],
52-
identityRoleType.GenericTypeArguments[2]));
53-
services.TryAddScoped(
54-
typeof(IRoleStore<>).MakeGenericType(roleType),
55-
typeof(RoleStore<,,,,>).MakeGenericType(roleType, contextType,
56-
identityRoleType.GenericTypeArguments[0],
57-
identityRoleType.GenericTypeArguments[1],
58-
identityRoleType.GenericTypeArguments[2]));
5995
}
6096

6197
private static TypeInfo FindGenericBaseType(Type currentType, Type genericBaseType)

src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/Properties/Resources.Designer.cs

Lines changed: 8 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)