ASP.NET   IDENTITY   Token based authentication 
▌背景
本篇重點在於延伸並客製OWIN Identity的Code First資料庫,以符合企業的內部需求。
▌相關文章
▌目標
在OWIN Identity的資料庫中,主要是以 AspNetUsers 這個表格儲存使用者的資訊,
我們目標是在
AspNetUsers 加上新的Foreign Key
Column,參照到其他Table。
以下是結果:
使用者多了兩個資訊:部門別和職位。
▌相關文章
▌環境
l   Visual Studio 2015
l   WEB API 2.2
l   Entity Framework 6
l   套件版本:
Microsoft.Owin.Host.SystemWeb 3.0.1
Microsoft.Owin.Host.SystemWeb 3.0.1
Microsoft ASP.NET Identity Owin 2.2.1
Microsoft ASP.NET Identity
EntityFramework 2.2.1
Microsoft ASP.NET Web API 2.2 OWIN
5.2.3
Microsoft.Owin.Security.OAuth 3.0.1
▌實作
▋Code First Database Model 
首先當然是建立Code First的Model~~ 
l   AspNetDepartment
| 
/// <summary> 
/// 部門(課) 
/// </summary> 
public class AspNetDepartment 
{ 
        /// Department Id 
        [Key] 
        [Required] 
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
        public Int32 AspNetDepartmentId { get; set; } 
        /// Department Name 
        [Required] 
        [Column(TypeName = "NVARCHAR")] 
        [MaxLength(100, ErrorMessage = "The legth of
  department's name must be 1~100")] 
        public String Name { get; set; } 
        /// AspNetDepartment 1..*
  EnhancedIdentityUser 
        public virtual ICollection<EnhancedIdentityUser>
  EnhancedIdentityUsers { get; set; }  
} | 
l   AspNetPositionLevel
| 
/// <summary> 
/// 職位 
/// </summary> 
public class AspNetPositionLevel 
{ 
        /// Position Level Id 
        [Key] 
        [Required] 
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
        public Int32 AspNetPositionLevelId { get; set; } 
        /// Position Level Name 
        [Required] 
        [Column(TypeName = "NVARCHAR")] 
        [MaxLength(100)] 
        public String Name { get; set; } 
        /// AspNetPositionLevel 1..*
  EnhancedIdentityUsers 
        public virtual ICollection<EnhancedIdentityUser>
  EnhancedIdentityUsers { get; set; }  
} | 
l   EnhancedIdentityUser
這是擴展IdentityUser的新Model,注意一定要加上constructor並呼叫基礎類別的建構。
這是擴展IdentityUser的新Model,注意一定要加上constructor並呼叫基礎類別的建構。
| 
/// IdentityUser的擴充 
public class EnhancedIdentityUser : IdentityUser 
{ /// Must inherit the base constructor 
        public EnhancedIdentityUser():base() 
        { 
        } 
        [Column(Order = 100)] 
        public Int32 AspNetDepartmentId { get; set; } 
        [Column(Order = 101)] 
        public Int32 AspNetPositionLevelId { get; set; } 
        //Foreign Key to AspNetDepartment 
        [ForeignKey("AspNetDepartmentId")] 
        public virtual AspNetDepartment AspNetDepartment
  { get; set; } 
        //Foreign Key to
  AspNetPositionLevel 
        [ForeignKey("AspNetPositionLevelId")] 
        public virtual AspNetPositionLevel
  AspNetPositionLevel { get; set; } 
} | 
▋更新DbContext 
更新DbContext是比較麻煩的地方,通常如果在Run-time
DB建不起來有99.999… % 是錯在這邊。
需要特別注意的地方:
需要特別注意的地方:
l   在覆寫(Override) OnModelCreating
這個方法時,必須呼叫基礎類別的OnModelCreating。
l   須建立上面資料表的一對多關聯。
完整 DbContext (這邊命名為AuthContext)
| 
public class AuthContext : IdentityDbContext<EnhancedIdentityUser> 
{ 
        public AuthContext() : base("AuthContext") 
        { 
        } 
        protected override void OnModelCreating(DbModelBuilder modelBuilder) 
        { 
            try 
            { 
                //MUST call the OnModelCreating
  method from base 
                base.OnModelCreating(modelBuilder); 
                #region Create relationship 
                //設定 PositionLevel 一對多 User 
                modelBuilder.Entity<AspNetPositionLevel>().HasMany(m
  => m.EnhancedIdentityUsers).WithRequired(m => m.AspNetPositionLevel); 
                //設定 Department 一對多 User 
                modelBuilder.Entity<AspNetDepartment>().HasMany(m
  => m.EnhancedIdentityUsers).WithRequired(m => m.AspNetDepartment); 
                #endregion 
                #region Create Index 
                //…  
                #endregion 
            } 
            catch (Exception ex) { } 
        } 
        //宣告資料模型: AspNetDepartments (由AspNetDepartment類別組成) 
        public DbSet<AspNetDepartment> AspNetDepartments
  { get; set; } 
        //宣告資料模型: AspNetPositionLevels (由AspNetPositionLevel類別組成) 
        public DbSet<AspNetPositionLevel>
  AspNetPositionLevels { get; set; } 
} | 
▋DB initialize (非必要)
或建立DB initialize的類別,並在Application Start時叫用。
| 
public class AuthContextInitializer : System.Data.Entity.CreateDatabaseIfNotExists<AuthContext> 
{ 
        protected override void Seed(AuthContext context) 
        { 
            try 
            { 
               
  context.AspNetDepartments.Add(new AspNetDepartment() { Name="應用一課" }); 
               
  context.AspNetDepartments.Add(new AspNetDepartment() { Name = "應用二課" }); 
               
  context.AspNetDepartments.Add(new AspNetDepartment() { Name = "應用三課" }); 
               
  context.AspNetPositionLevels.Add(new AspNetPositionLevel() { Name = "助理工程師" }); 
                context.AspNetPositionLevels.Add(new AspNetPositionLevel() { Name = "工程師" }); 
               
  context.AspNetPositionLevels.Add(new AspNetPositionLevel() { Name = "資深工程師" }); 
               
  context.AspNetPositionLevels.Add(new AspNetPositionLevel() { Name = "主任工程師" }); 
                context.SaveChanges(); 
            } 
            catch (Exception ex) { } 
        } 
    } | 
Global.asax
| 
protected void
  Application_Start() 
{ 
    // … 
    //註冊資料庫Initial 
    Database.SetInitializer(new AuthContextInitializer()); 
} | 
▋更新 DTO : UserModel
還記得Identity WebApi 的DTO物件: UserModel嗎?
別忘記加上新欄位囉!
| 
public class UserModel 
{ 
        [Required] 
        [Display(Name = "User Name")] 
        public String UserName { get; set; } 
        [Required] 
        [StringLength(100,
  MinimumLength = 6, ErrorMessage = "The {0}'s length must be between {2}~{1}
  characters long")] 
        [DataType(DataType.Password)] 
        [Display(Name = "Password")] 
        public String Password { get; set; } 
        [DataType(DataType.Password)] 
        [Display(Name = "Confirm password")] 
        [Compare("Password", ErrorMessage = "The password
  and confirmation password do not match.")] 
        public String ConfirmPassword { get; set; } 
        [Required] 
        [Display(Name = "Department Id")] 
        public Int32 DepartmentId { get; set; } 
        [Required] 
        [Display(Name = "Position Level Id")] 
        public Int32 PositionLevelId { get; set; } 
} | 
▋更新 Authentication Repository
別忘記以新的Model 更新CRUD的Repository!
IdentityUser 全部取代為 EnhancedIdentityUser!
另外,也記得在 RegisterUser這個方法 (亦即建立使用者時),
從前端回拋的資料指定回DB Model。
▌測試
更新後的資料庫:
2.  Unregister
▌Reference
無







 
沒有留言:
張貼留言