自定义OWIN / Katana UserManager工厂行为

时间:2015-01-07 17:22:52

标签: asp.net entity-framework asp.net-identity owin katana

有很多样本在线使用OWIN / Katana根据用户名/密码组合查找数据库中的用户并生成索赔主体,例如......

var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
// generate claims here...

如果您正在创建新的应用程序并希望实体框架执行肮脏的工作,那就没问题了。但是,我有一个八年历史的单片网站刚刚更新,使用基于声明的身份验证。我们的数据库命中是通过DAL / SQL手动完成的,然后从那里生成ClaimsIdentity。

有些人建议OWIN比我们的手动方法更容易使用,但我想要使用它的人提供一些意见。

是否可以根据凭据更改UserManager工厂查找用户的方式?或者,还有其他方法我错过了吗?我在网上找到的所有样本似乎都使用样板方法让Entity Framework创建数据库并管理搜索。

1 个答案:

答案 0 :(得分:13)

我会说,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 )。

然后,您必须定义继承自UserManager的自定义Microsoft.AspNet.Identity.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)
{
}

等等。

然后,您需要定义继承自SignInManager的{​​{1}}。

Microsoft.AspNet.Identity.Owin.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); } } :它会生成ClaimsIdentity

那就是它。

现在,在SignInAsync课程中,您必须告诉Startup如何创建OwinUserManager

SignInManager

我没有使用您在默认模板中找到的工厂,因为我希望尽可能简化

并使您的应用程序能够使用cookie:

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));

现在,在您的帐户控制器中 - 或负责登录的控制器 - 您必须获得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

看起来很复杂......而且......有点......

如果您想了解更多相关信息,可以获得一个很好的解释herehere

如果你想运行一些代码并看看它是如何工作的,我已经整理了一些与code一起使用的Biggy(因为我并不想浪费太多时间定义表和类似的东西)。

如果您有机会从github repo下载我的代码,您会注意到我已经创建了一个辅助项目(Custom.Identity),我保留了所有 ASP.NET身份的东西。

您需要的唯一 nuget 套餐包括:

  1. Microsoft.AspNet.Identity.Core
  2. Microsoft.AspNet.Identity.Owin