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
無
沒有留言:
張貼留言