Last active
March 20, 2016 20:28
-
-
Save weitzhandler/f9ebca6936ed0489d42d to your computer and use it in GitHub Desktop.
Microsoft.AspNet.EntityFramework.Identity.Multitenant
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"version": "2.0.0-alpha-1", | |
"description": "Identity.Multitenant Class Library", | |
"authors": [ "JSkimmer", "Shimmy" ], | |
"tags": [ "" ], | |
"projectUrl": "", | |
"licenseUrl": "", | |
"dependencies": { | |
"System.Runtime": "4.0.20-beta-23019", | |
"Microsoft.AspNet.Identity.EntityFramework": "3.0.0-beta5" | |
}, | |
"frameworks": { | |
"dnx451": { }, | |
"dnxcore50": { } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.AspNet.Identity.EntityFramework.Tenant; | |
using Microsoft.AspNet.Routing; | |
using System; | |
using System.Collections.Generic; | |
using System.ComponentModel.DataAnnotations; | |
using System.ComponentModel.DataAnnotations.Schema; | |
using System.Linq; | |
using System.Threading.Tasks; | |
namespace Microsoft.AspNet.Identity.EntityFramework.Tenant | |
{ | |
public class Tenant : Tenant<string> | |
{ | |
} | |
/// <summary> | |
/// A class that encapsulates an organization. | |
/// </summary> | |
public class Tenant<TKey> : IValidatableObject | |
where TKey : IEquatable<TKey> | |
{ | |
//TODO: should retrieve from config.json AppSettings.ReservedSubdomains | |
public static string[] ReservedTenantNames = new string[] { "www", "global", "info", "admin" }; | |
[Key] | |
public virtual TKey Id { get; set; } | |
[RegularExpression(@"[a-z0-9\-]+")] | |
[StringLength(16, MinimumLength = 6)] | |
public virtual string TenantName { get; set; } | |
public virtual ICollection<TenantUser<TKey>> Users { get; set; } = new HashSet<TenantUser<TKey>>(); | |
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) | |
{ | |
if (ReservedTenantNames.Contains(TenantName)) | |
yield return new ValidationResult($"The tenant name {TenantName} is reserved."); | |
yield return ValidationResult.Success; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using Microsoft.Data.Entity; | |
using Microsoft.Data.Entity.Metadata; | |
namespace Microsoft.AspNet.Identity.EntityFramework.Tenant | |
{ | |
public class TenantIdentityDbContext | |
: TenantIdentityDbContext<TenantUser, IdentityRole, Tenant, string, | |
TenantUserLogin, IdentityUserRole, IdentityUserClaim> | |
{ | |
} | |
public class TenantIdentityDbContext<TUser, TRole, TTenant, TKey, TUserLogin, TUserRole, TUserClaim> | |
: IdentityDbContext<TUser, TRole, TKey> | |
where TUser : TenantUser<TKey> | |
where TRole : IdentityRole<TKey> | |
where TTenant : Tenant<TKey> | |
where TKey : IEquatable<TKey> | |
where TUserLogin : TenantUserLogin<TKey>, new() | |
{ | |
public DbSet<TTenant> Tenants { get; set; } | |
protected override void OnModelCreating(ModelBuilder builder) | |
{ | |
//hack to avoid duplicate generations of the following | |
builder.Model.RemoveEntityType(builder.Entity<IdentityUserLogin<TKey>>().Metadata); | |
builder.Model.RemoveEntityType(builder.Entity<IdentityUser<TKey>>().Metadata); | |
builder.Entity<TUser>(b => | |
{ | |
b.Key(u => u.Id); | |
b.Index(u => u.NormalizedUserName).Unique().IndexName("UserNameIndex"); | |
b.Index(u => u.NormalizedEmail).IndexName("EmailIndex"); | |
b.Index(u => new { u.UserName, u.TenantId }).Unique().IndexName("UserTenantIndex"); | |
b.ToTable("Users"); | |
b.Property(u => u.ConcurrencyStamp).ConcurrencyToken(); | |
b.Property(u => u.UserName).MaxLength(16); | |
b.Property(u => u.NormalizedUserName).MaxLength(16); | |
b.Property(u => u.Email).MaxLength(256); | |
b.Property(u => u.NormalizedEmail).MaxLength(256); | |
b.Property(u => u.TenantId).Required(); | |
b.Collection(u => u.Claims).InverseReference().ForeignKey(uc => uc.UserId); | |
b.Collection(u => u.Roles).InverseReference().ForeignKey(ur => ur.UserId); | |
b.Reference(u => u.Tenant); | |
}); | |
builder.Entity<TRole>(b => | |
{ | |
b.Key(r => r.Id); | |
b.Index(r => r.NormalizedName).IndexName("RoleNameIndex"); | |
b.ToTable("Roles"); | |
b.Property(r => r.ConcurrencyStamp).ConcurrencyToken(); | |
b.Property(u => u.Name).MaxLength(256); | |
b.Property(u => u.NormalizedName).MaxLength(256); | |
b.Collection(r => r.Users).InverseReference().ForeignKey(ur => ur.RoleId); | |
b.Collection(r => r.Claims).InverseReference().ForeignKey(rc => rc.RoleId); | |
}); | |
builder.Entity<TTenant>(b => | |
{ | |
b.Key(t => t.Id); | |
b.Index(t => t.TenantName).Unique().IndexName("TenantNameIndex"); | |
b.ToTable("Tenants"); | |
b.Collection(t => t.Users).InverseReference().ForeignKey(u => u.TenantId); | |
}); | |
builder.Entity<IdentityUserClaim<TKey>>(b => | |
{ | |
b.Key(uc => uc.Id); | |
b.ToTable("Claims"); | |
}); | |
builder.Entity<TUserLogin>(b => | |
{ | |
b.Key(ul => | |
new | |
{ | |
ul.LoginProvider, | |
ul.ProviderKey, | |
ul.UserId, | |
ul.TenantId, | |
}); | |
}); | |
builder.Entity<IdentityRoleClaim<TKey>>(b => | |
{ | |
b.Key(rc => rc.Id); | |
b.ToTable("RoleClaims"); | |
}); | |
builder.Entity<IdentityUserRole<TKey>>(b => | |
{ | |
b.Key(r => new { r.UserId, r.RoleId }); | |
b.ToTable("UserRoles"); | |
}); | |
// Blocks delete currently without cascade | |
//.ForeignKeys(fk => fk.ForeignKey<TUser>(f => f.UserId)) | |
//.ForeignKeys(fk => fk.ForeignKey<TRole>(f => f.RoleId)); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.ComponentModel.DataAnnotations; | |
using System.ComponentModel.DataAnnotations.Schema; | |
using System.Linq; | |
using System.Threading.Tasks; | |
namespace Microsoft.AspNet.Identity.EntityFramework.Tenant | |
{ | |
public class TenantUser : TenantUser<string> | |
{ | |
public TenantUser() | |
{ | |
Id = Guid.NewGuid().ToString(); | |
} | |
} | |
public class TenantUser<TKey> : IdentityUser<TKey> | |
where TKey : IEquatable<TKey> | |
{ | |
public virtual TKey TenantId { get; set; } | |
public virtual Tenant<TKey> Tenant { get; set; } | |
/// <summary> | |
/// Navigation property for users logins. | |
/// </summary> | |
public new ICollection<TenantUserLogin<TKey>> Logins { get; } = new HashSet<TenantUserLogin<TKey>>(); | |
} | |
public class TenantUserValidator : TenantUserValidator<string> | |
{ | |
} | |
public class TenantUserValidator<TKey> : UserValidator<TenantUser<TKey>> | |
where TKey : IEquatable<TKey> | |
{ | |
public override Task<IdentityResult> ValidateAsync(UserManager<TenantUser<TKey>> manager, TenantUser<TKey> user) | |
{ | |
return base.ValidateAsync(manager, user); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
namespace Microsoft.AspNet.Identity.EntityFramework.Tenant | |
{ | |
public class TenantUserLogin : TenantUserLogin<string, string> | |
{ | |
} | |
public class TenantUserLogin<TKey, TTenantKey> : IdentityUserLogin<TKey> | |
where TKey : IEquatable<TKey> | |
where TTenantKey : IEquatable<TTenantKey> | |
{ | |
public TTenantKey TenantId { get; set; } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.Data.Entity; | |
using System; | |
using System.Threading; | |
using System.Threading.Tasks; | |
namespace Microsoft.AspNet.Identity.EntityFramework.Tenant | |
{ | |
public class TenantUserStore : TenantUserStore<TenantIdentityDbContext> | |
{ | |
public TenantUserStore(TenantIdentityDbContext context) | |
: base(context) | |
{ | |
} | |
} | |
public class TenantUserStore<TContext> : TenantUserStore<TenantUser, IdentityRole, Tenant, TContext, TenantUserLogin, IdentityUserRole, IdentityUserClaim> | |
where TContext : TenantIdentityDbContext<TenantUser, IdentityRole, Tenant, string, TenantUserLogin, IdentityUserRole, IdentityUserClaim> | |
{ | |
public TenantUserStore(TContext context) | |
: base(context) | |
{ | |
} | |
} | |
public class TenantUserStore<TUser, TRole, TTenant, TContext, TUserLogin, TUserRole, TUserClaim> | |
: TenantUserStore<TUser, TRole, TTenant, TContext, string, TUserLogin, TUserRole, TUserClaim> | |
where TUser : TenantUser | |
where TRole : IdentityRole | |
where TTenant : Tenant | |
where TContext : TenantIdentityDbContext<TUser, TRole, TTenant, string, TUserLogin, TUserRole, TUserClaim> | |
where TUserLogin : TenantUserLogin, new() | |
where TUserRole : IdentityUserRole, new() | |
where TUserClaim : IdentityUserClaim, new() | |
{ | |
public TenantUserStore(TContext context) | |
: base(context) | |
{ | |
} | |
} | |
public class TenantUserStore< | |
TUser, TRole, TTenant, TContext, TKey, | |
TUserLogin, TUserRole, TUserClaim> | |
: UserStore<TUser, TRole, TContext, TKey> | |
where TUser : TenantUser<TKey> | |
where TRole : IdentityRole<TKey> | |
where TTenant : Tenant<TKey> | |
where TContext : TenantIdentityDbContext< | |
TUser, TRole, TTenant, TKey, TUserLogin, TUserRole, TUserClaim> | |
where TKey : IEquatable<TKey> | |
where TUserLogin : TenantUserLogin<TKey>, new() | |
where TUserRole : IdentityUserRole<TKey>, new() | |
where TUserClaim : IdentityUserClaim<TKey>, new() | |
{ | |
public TenantUserStore(TContext context) | |
: base(context) | |
{ | |
} | |
private DbSet<TUserLogin> _Logins; | |
public DbSet<TUserLogin> Logins | |
{ | |
get | |
{ | |
return _Logins ?? (_Logins = Context.Set<TUserLogin>()); | |
} | |
} | |
public override Task<IdentityResult> CreateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) | |
{ | |
return base.CreateAsync(user, cancellationToken); | |
} | |
public override Task<TUser> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken = default(CancellationToken)) | |
{ | |
return base.FindByNameAsync(normalizedUserName, cancellationToken); | |
} | |
public override Task<TUser> FindByIdAsync(string userId, CancellationToken cancellationToken = default(CancellationToken)) | |
{ | |
return base.FindByIdAsync(userId, cancellationToken); | |
} | |
public override Task AddLoginAsync(TUser user, UserLoginInfo login, CancellationToken cancellationToken = default(CancellationToken)) | |
{ | |
return base.AddLoginAsync(user, login, cancellationToken); | |
} | |
public override Task<TUser> FindByEmailAsync(string normalizedEmail, CancellationToken cancellationToken = default(CancellationToken)) | |
{ | |
return base.FindByEmailAsync(normalizedEmail, cancellationToken); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment