您好,登錄后才能下訂單哦!
本篇文章為大家展示了使用EF6怎么實現一個多租戶應用,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
什么是多租戶
網上有好多解釋,有些上升到了架構設計,讓你覺得似乎非常高深莫測,特別是目前流行的ABP架構中就有提到多租戶(IMustHaveTenant),其實說的簡單一點就是再每一張數據庫的表中添加一個TenantId的字段,用于區分屬于不同的租戶(或是說不同的用戶組)的數據。關鍵是現實的方式必須對開發人員來說是透明的,不需要關注這個字段的信息,由后臺或是封裝在基類中實現數據的篩選和更新。
基本原理
從新用戶注冊時就必須指定用戶的TenantId,我的例子是用CompanyId,公司信息做為TenantId,哪些用戶屬于不同的公司,每個用戶將來只能修改和查詢屬于本公司的數據。
接下來就是用戶登錄的時候獲取用戶信息的時候把TenantId保存起來,asp.net mvc(不是 core) 是通過 Identity 2.0實現的認證和授權,這里需要重寫部分代碼來實現。
最后用戶對數據查詢/修改/新增時把用戶信息中TenantId,這里就需要設定一個Filter(過濾器)和每次SaveChange的插入TenantId
如何實現
第一步,擴展 Asp.net Identity user 屬性,必須新增一個TenantId字段,根據Asp.net Mvc 自帶的項目模板修改IdentityModels.cs 這個文件
// You can add profile data for the user by adding more properties to your ApplicationUser class, please visit http://go.microsoft.com/fwlink/?LinkID=317594 to learn more. public class ApplicationUser : IdentityUser { public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager, string authenticationType) { // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType var userIdentity = await manager.CreateIdentityAsync(this, authenticationType); // Add custom user claims here userIdentity.AddClaim(new Claim("http://schemas.microsoft.com/identity/claims/tenantid", this.TenantId.ToString())); userIdentity.AddClaim(new Claim("CompanyName", this.CompanyName)); userIdentity.AddClaim(new Claim("EnabledChat", this.EnabledChat.ToString())); userIdentity.AddClaim(new Claim("FullName", this.FullName)); userIdentity.AddClaim(new Claim("AvatarsX50", this.AvatarsX50)); userIdentity.AddClaim(new Claim("AvatarsX120", this.AvatarsX120)); return userIdentity; } public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager) { // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie); // Add custom user claims here return userIdentity; } [Display(Name = "全名")] public string FullName { get; set; } [Display(Name = "性別")] public int Gender { get; set; } public int AccountType { get; set; } [Display(Name = "所屬公司")] public string CompanyCode { get; set; } [Display(Name = "公司名稱")] public string CompanyName { get; set; } [Display(Name = "是否在線")] public bool IsOnline { get; set; } [Display(Name = "是否開啟聊天功能")] public bool EnabledChat { get; set; } [Display(Name = "小頭像")] public string AvatarsX50 { get; set; } [Display(Name = "大頭像")] public string AvatarsX120 { get; set; } [Display(Name = "租戶ID")] public int TenantId { get; set; } } public class ApplicationDbContext : IdentityDbContext<ApplicationUser> { public ApplicationDbContext() : base("DefaultConnection", throwIfV1Schema: false) => Database.SetInitializer<ApplicationDbContext>(null); public static ApplicationDbContext Create() => new ApplicationDbContext(); }
第二步 修改注冊用戶的代碼,注冊新用戶的時候需要選擇所屬的公司信息
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Register(AccountRegistrationModel viewModel) { var data = this._companyService.Queryable().Select(x => new ListItem() { Value = x.Id.ToString(), Text = x.Name }); this.ViewBag.companylist = data; // Ensure we have a valid viewModel to work with if (!this.ModelState.IsValid) { return this.View(viewModel); } // Try to create a user with the given identity try { // Prepare the identity with the provided information var user = new ApplicationUser { UserName = viewModel.Username, FullName = viewModel.Lastname + "." + viewModel.Firstname, CompanyCode = viewModel.CompanyCode, CompanyName = viewModel.CompanyName, TenantId=viewModel.TenantId, Email = viewModel.Email, AccountType = 0 }; var result = await this.UserManager.CreateAsync(user, viewModel.Password); // If the user could not be created if (!result.Succeeded) { // Add all errors to the page so they can be used to display what went wrong this.AddErrors(result); return this.View(viewModel); } // If the user was able to be created we can sign it in immediately // Note: Consider using the email verification proces await this.SignInAsync(user, true); return this.RedirectToLocal(); } catch (DbEntityValidationException ex) { // Add all errors to the page so they can be used to display what went wrong this.AddErrors(ex); return this.View(viewModel); } } AccountController.cs
第三步 讀取登錄用戶的TenantId 在用戶查詢和新增修改時把TenantId插入到表中,這里需要引用
Z.EntityFramework.Plus,這個是免費開源的一個類庫,功能強大
public StoreContext() : base("Name=DefaultConnection") { //獲取登錄用戶信息,tenantid var claimsidentity = (ClaimsIdentity)HttpContext.Current.User.Identity; var tenantclaim = claimsidentity?.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid"); var tenantid = Convert.ToInt32(tenantclaim?.Value); //設置當對Work對象進行查詢時默認添加過濾條件 QueryFilterManager.Filter<Work>(q => q.Where(x => x.TenantId == tenantid)); //設置當對Order對象進行查詢時默認添加過濾條件 QueryFilterManager.Filter<Order>(q => q.Where(x => x.TenantId == tenantid)); } public override Task<int> SaveChangesAsync(CancellationToken cancellationToken) { var currentDateTime = DateTime.Now; var claimsidentity = (ClaimsIdentity)HttpContext.Current.User.Identity; var tenantclaim = claimsidentity?.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid"); var tenantid = Convert.ToInt32(tenantclaim?.Value); foreach (var auditableEntity in this.ChangeTracker.Entries<Entity>()) { if (auditableEntity.State == EntityState.Added || auditableEntity.State == EntityState.Modified) { //auditableEntity.Entity.LastModifiedDate = currentDateTime; switch (auditableEntity.State) { case EntityState.Added: auditableEntity.Property("LastModifiedDate").IsModified = false; auditableEntity.Property("LastModifiedBy").IsModified = false; auditableEntity.Entity.CreatedDate = currentDateTime; auditableEntity.Entity.CreatedBy = claimsidentity.Name; auditableEntity.Entity.TenantId = tenantid; break; case EntityState.Modified: auditableEntity.Property("CreatedDate").IsModified = false; auditableEntity.Property("CreatedBy").IsModified = false; auditableEntity.Entity.LastModifiedDate = currentDateTime; auditableEntity.Entity.LastModifiedBy = claimsidentity.Name; auditableEntity.Entity.TenantId = tenantid; //if (auditableEntity.Property(p => p.Created).IsModified || auditableEntity.Property(p => p.CreatedBy).IsModified) //{ // throw new DbEntityValidationException(string.Format("Attempt to change created audit trails on a modified {0}", auditableEntity.Entity.GetType().FullName)); //} break; } } } return base.SaveChangesAsync(cancellationToken); } public override int SaveChanges() { var currentDateTime = DateTime.Now; var claimsidentity =(ClaimsIdentity)HttpContext.Current.User.Identity; var tenantclaim = claimsidentity?.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid"); var tenantid = Convert.ToInt32(tenantclaim?.Value); foreach (var auditableEntity in this.ChangeTracker.Entries<Entity>()) { if (auditableEntity.State == EntityState.Added || auditableEntity.State == EntityState.Modified) { auditableEntity.Entity.LastModifiedDate = currentDateTime; switch (auditableEntity.State) { case EntityState.Added: auditableEntity.Property("LastModifiedDate").IsModified = false; auditableEntity.Property("LastModifiedBy").IsModified = false; auditableEntity.Entity.CreatedDate = currentDateTime; auditableEntity.Entity.CreatedBy = claimsidentity.Name; auditableEntity.Entity.TenantId = tenantid; break; case EntityState.Modified: auditableEntity.Property("CreatedDate").IsModified = false; auditableEntity.Property("CreatedBy").IsModified = false; auditableEntity.Entity.LastModifiedDate = currentDateTime; auditableEntity.Entity.LastModifiedBy = claimsidentity.Name; auditableEntity.Entity.TenantId = tenantid; break; } } } return base.SaveChanges(); } DbContext.cs
上述內容就是使用EF6怎么實現一個多租戶應用,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。