自定义 OWIN/Katana UserManager 工厂行为
Customising the OWIN/Katana UserManager factory behaviour
网上有很多示例使用OWIN/Katana根据ausername/password组合在数据库中查找用户并生成声明主体,例如...
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
// generate claims here...
如果您要创建一个新应用程序并希望 Entity Framework 完成繁琐的工作,那很好。但是,我有一个八年前的单体网站,刚刚更新为使用基于声明的身份验证。我们的数据库命中是通过 DAL/SQL 手动完成的,然后从那里生成 ClaimsIdentity。
有些人认为 OWIN 比我们的手动方法更易于使用,但我希望使用它的人提供一些意见。
是否可以更改 UserManager 工厂根据凭据查找用户的方式?或者,有没有我错过的另一种方法?我可以在网上找到的所有示例似乎都使用了让 Entity Framework 创建数据库和管理搜索的样板方法。
ASP.NET 身份有点过于复杂,我想说。
2014 年 8 月,他们宣布了新版本 2.1,情况又发生了变化。
首先让我们去掉 EntityFramework
:
Uninstall-Package Microsoft.AspNet.Identity.EntityFramework
现在我们实现自己定义的User
实现接口IUser
(Microsoft.AspNet.Identity):
public class User: IUser<int>
{
public User()
{
this.Roles = new List<string>();
this.Claims = new List<UserClaim>();
}
public User(string userName)
: this()
{
this.UserName = userName;
}
public User(int id, string userName): this()
{
this.Id = Id;
this.UserName = userName;
}
public int Id { get; set; }
public string UserName { get; set; }
public string PasswordHash { get; set; }
public bool LockoutEnabled { get; set; }
public DateTime? LockoutEndDateUtc { get; set; }
public bool TwoFactorEnabled { get; set; }
public IList<string> Roles { get; private set; }
public IList<UserClaim> Claims { get; private set; }
}
如您所见,我已经定义了 Id
(int) 的类型。
然后您必须定义继承自 Microsoft.AspNet.Identity.UserManager
的自定义 UserManager
,指定您的用户类型和密钥类型。
public class UserManager : UserManager<User, int>
{
public UserManager(IUserStore<User, int> store): base(store)
{
this.UserLockoutEnabledByDefault = false;
// this.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(10);
// this.MaxFailedAccessAttemptsBeforeLockout = 10;
this.UserValidator = new UserValidator<User, int>(this)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = false
};
// Configure validation logic for passwords
this.PasswordValidator = new PasswordValidator
{
RequiredLength = 4,
RequireNonLetterOrDigit = false,
RequireDigit = false,
RequireLowercase = false,
RequireUppercase = false,
};
}
}
我已经在此处实施了我的验证规则,但如果您愿意,可以将其放在外面。
UserManager
需要一个 UserStore
(IUserStore).
您将在此处定义您的数据库逻辑。有几个接口要实现。不过,并非所有这些都是强制性的。
public class UserStore :
IUserStore<User, int>,
IUserPasswordStore<User, int>,
IUserLockoutStore<User, int>,
IUserTwoFactorStore<User, int>,
IUserRoleStore<User, int>,
IUserClaimStore<User, int>
{
// You can inject connection string or db session
public UserStore()
{
}
}
我没有包括每个接口的所有方法。一旦你完成了,你就可以写你的新用户:
public System.Threading.Tasks.Task CreateAsync(User user)
{
}
通过 Id 获取:
public System.Threading.Tasks.Task<User> FindByIdAsync(int userId)
{
}
等等。
然后您需要定义继承自 Microsoft.AspNet.Identity.Owin.SignInManager
的 SignInManager
。
public class SignInManager: SignInManager<User, int>
{
public SignInManager(UserManager userManager, IAuthenticationManager authenticationManager): base(userManager, authenticationManager)
{
}
public override Task SignInAsync(User user, bool isPersistent, bool rememberBrowser)
{
return base.SignInAsync(user, isPersistent, rememberBrowser);
}
}
我只实现了 SignInAsync
:它会生成一个 ClaimsIdentity.
差不多就这些了。
现在在你的 Startup
class 中你必须告诉 Owin
如何创建 UserManager
和 SignInManager
.
app.CreatePerOwinContext<Custom.Identity.UserManager>(() => new Custom.Identity.UserManager(new Custom.Identity.UserStore()));
// app.CreatePerOwinContext<Custom.Identity.RoleManager>(() => new Custom.Identity.RoleManager(new Custom.Identity.RoleStore()));
app.CreatePerOwinContext<Custom.Identity.SignInService>((options, context) => new Custom.Identity.SignInService(context.GetUserManager<Custom.Identity.UserManager>(), context.Authentication));
我没有使用默认模板中的工厂,因为我想让事情尽可能简单。
并使您的应用程序能够使用 cookie:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<Custom.Identity.UserManager, Custom.Identity.User, int>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentityCallback: (manager, user) =>
{
var userIdentity = manager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
return (userIdentity);
},
getUserIdCallback: (id) => (Int32.Parse(id.GetUserId()))
)}
});
现在在您的帐户控制器 - 或负责登录的控制器 - 您将必须获得 UserManager
和 SignInManager
:
public Custom.Identity.SignInManager SignInManager
{
get
{
return HttpContext.GetOwinContext().Get<Custom.Identity.SignInManager>();
}
}
public Custom.Identity.UserManager UserManager
{
get
{
return HttpContext.GetOwinContext().GetUserManager<Custom.Identity.UserManager>();
}
}
您将使用 SignInManager
进行登录:
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
和UserManager
创建用户,添加角色和声明:
if (ModelState.IsValid)
{
var user = new Custom.Identity.User() { UserName = model.Email };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
// await UserManager.AddToRoleAsync(user.Id, "Administrators");
// await UserManager.AddClaimAsync(user.Id, new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Country, "England"));
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
它看起来很复杂......而且它是......有点。
如果您想阅读更多相关信息,可以找到很好的解释 here and here。
如果你想 运行 一些代码并看看它是如何工作的,我已经整理了一些 code which works with Biggy(因为我不想浪费太多时间来定义表格和类似的东西那)。
如果您有机会从 github 存储库下载我的代码,您会注意到我创建了一个辅助项目 (Custom.Identity),我将所有 ASP.NET 身份 东西。
您唯一需要的 nuget 包有:
- Microsoft.AspNet.Identity.核心
- Microsoft.AspNet.Identity.欧文
网上有很多示例使用OWIN/Katana根据ausername/password组合在数据库中查找用户并生成声明主体,例如...
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
// generate claims here...
如果您要创建一个新应用程序并希望 Entity Framework 完成繁琐的工作,那很好。但是,我有一个八年前的单体网站,刚刚更新为使用基于声明的身份验证。我们的数据库命中是通过 DAL/SQL 手动完成的,然后从那里生成 ClaimsIdentity。
有些人认为 OWIN 比我们的手动方法更易于使用,但我希望使用它的人提供一些意见。
是否可以更改 UserManager 工厂根据凭据查找用户的方式?或者,有没有我错过的另一种方法?我可以在网上找到的所有示例似乎都使用了让 Entity Framework 创建数据库和管理搜索的样板方法。
ASP.NET 身份有点过于复杂,我想说。
2014 年 8 月,他们宣布了新版本 2.1,情况又发生了变化。
首先让我们去掉 EntityFramework
:
Uninstall-Package Microsoft.AspNet.Identity.EntityFramework
现在我们实现自己定义的User
实现接口IUser
(Microsoft.AspNet.Identity):
public class User: IUser<int>
{
public User()
{
this.Roles = new List<string>();
this.Claims = new List<UserClaim>();
}
public User(string userName)
: this()
{
this.UserName = userName;
}
public User(int id, string userName): this()
{
this.Id = Id;
this.UserName = userName;
}
public int Id { get; set; }
public string UserName { get; set; }
public string PasswordHash { get; set; }
public bool LockoutEnabled { get; set; }
public DateTime? LockoutEndDateUtc { get; set; }
public bool TwoFactorEnabled { get; set; }
public IList<string> Roles { get; private set; }
public IList<UserClaim> Claims { get; private set; }
}
如您所见,我已经定义了 Id
(int) 的类型。
然后您必须定义继承自 Microsoft.AspNet.Identity.UserManager
的自定义 UserManager
,指定您的用户类型和密钥类型。
public class UserManager : UserManager<User, int>
{
public UserManager(IUserStore<User, int> store): base(store)
{
this.UserLockoutEnabledByDefault = false;
// this.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(10);
// this.MaxFailedAccessAttemptsBeforeLockout = 10;
this.UserValidator = new UserValidator<User, int>(this)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = false
};
// Configure validation logic for passwords
this.PasswordValidator = new PasswordValidator
{
RequiredLength = 4,
RequireNonLetterOrDigit = false,
RequireDigit = false,
RequireLowercase = false,
RequireUppercase = false,
};
}
}
我已经在此处实施了我的验证规则,但如果您愿意,可以将其放在外面。
UserManager
需要一个 UserStore
(IUserStore).
您将在此处定义您的数据库逻辑。有几个接口要实现。不过,并非所有这些都是强制性的。
public class UserStore :
IUserStore<User, int>,
IUserPasswordStore<User, int>,
IUserLockoutStore<User, int>,
IUserTwoFactorStore<User, int>,
IUserRoleStore<User, int>,
IUserClaimStore<User, int>
{
// You can inject connection string or db session
public UserStore()
{
}
}
我没有包括每个接口的所有方法。一旦你完成了,你就可以写你的新用户:
public System.Threading.Tasks.Task CreateAsync(User user)
{
}
通过 Id 获取:
public System.Threading.Tasks.Task<User> FindByIdAsync(int userId)
{
}
等等。
然后您需要定义继承自 Microsoft.AspNet.Identity.Owin.SignInManager
的 SignInManager
。
public class SignInManager: SignInManager<User, int>
{
public SignInManager(UserManager userManager, IAuthenticationManager authenticationManager): base(userManager, authenticationManager)
{
}
public override Task SignInAsync(User user, bool isPersistent, bool rememberBrowser)
{
return base.SignInAsync(user, isPersistent, rememberBrowser);
}
}
我只实现了 SignInAsync
:它会生成一个 ClaimsIdentity.
差不多就这些了。
现在在你的 Startup
class 中你必须告诉 Owin
如何创建 UserManager
和 SignInManager
.
app.CreatePerOwinContext<Custom.Identity.UserManager>(() => new Custom.Identity.UserManager(new Custom.Identity.UserStore()));
// app.CreatePerOwinContext<Custom.Identity.RoleManager>(() => new Custom.Identity.RoleManager(new Custom.Identity.RoleStore()));
app.CreatePerOwinContext<Custom.Identity.SignInService>((options, context) => new Custom.Identity.SignInService(context.GetUserManager<Custom.Identity.UserManager>(), context.Authentication));
我没有使用默认模板中的工厂,因为我想让事情尽可能简单。
并使您的应用程序能够使用 cookie:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<Custom.Identity.UserManager, Custom.Identity.User, int>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentityCallback: (manager, user) =>
{
var userIdentity = manager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
return (userIdentity);
},
getUserIdCallback: (id) => (Int32.Parse(id.GetUserId()))
)}
});
现在在您的帐户控制器 - 或负责登录的控制器 - 您将必须获得 UserManager
和 SignInManager
:
public Custom.Identity.SignInManager SignInManager
{
get
{
return HttpContext.GetOwinContext().Get<Custom.Identity.SignInManager>();
}
}
public Custom.Identity.UserManager UserManager
{
get
{
return HttpContext.GetOwinContext().GetUserManager<Custom.Identity.UserManager>();
}
}
您将使用 SignInManager
进行登录:
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
和UserManager
创建用户,添加角色和声明:
if (ModelState.IsValid)
{
var user = new Custom.Identity.User() { UserName = model.Email };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
// await UserManager.AddToRoleAsync(user.Id, "Administrators");
// await UserManager.AddClaimAsync(user.Id, new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Country, "England"));
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
它看起来很复杂......而且它是......有点。
如果您想阅读更多相关信息,可以找到很好的解释 here and here。
如果你想 运行 一些代码并看看它是如何工作的,我已经整理了一些 code which works with Biggy(因为我不想浪费太多时间来定义表格和类似的东西那)。
如果您有机会从 github 存储库下载我的代码,您会注意到我创建了一个辅助项目 (Custom.Identity),我将所有 ASP.NET 身份 东西。
您唯一需要的 nuget 包有:
- Microsoft.AspNet.Identity.核心
- Microsoft.AspNet.Identity.欧文