实现UserManager以使用自定义类和存储过程

时间:2015-06-14 02:53:05

标签: .net asp.net-mvc asp.net-identity asp.net-identity-2

我的应用程序的所有身份验证和授权过程都是使用存储过程完成的。我写了一个包含我需要的所有功能的课程,例如GetUsersLoginAddRoleAddMember等 此外,管理用户,角色和权限的管理页面也是使用此类完成的。

我只需要添加authentication(我的意思是authorize属性),用于登录和注销的cookie以及为每个登录存储一些服务器端数据。我想我需要为此实现Identity

在这种情况下,您可以指导我实施吗?您需要做的最基本的事情是实现一个create方法,将IUserStore的实例传递给构造函数。但是我不需要为用户或角色提供任何表,我该如何实现这种方法?

这是当前的类,如果您需要查看使用存储过程的自定义身份验证类,请告诉我。

public class AppUserManager : UserManager<AppUser>
{
    public AppUserManager(IUserStore<AppUser> store) : base(store) { }
    public static AppUserManager Create(IdentityFactoryOptions<AppUserManager> options, IOwinContext context)
    {
        //AppUserManager manager = new AppUserManager();
        //return manager;
        return null;
    }
}

3 个答案:

答案 0 :(得分:7)

由于alisabzevari建议您必须实施IUserStore 您甚至不依赖于定义的存储和表结构。 您可以自定义存储层的每个位。

我做了一些实验并试图使用不同的存储空间来实现我自己的UserManagerRoleManager,例如Biggy

  

基于文件的.NET文档存储。

您可以在GitHub上找到代码here

首先要实现的是UserManager,您可以在其中配置密码验证的要求:

public class AppUserManager : UserManager<AppUser, int>
{
    public AppUserManager (IUserStore<AppUser, 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,
        };
    }
}

然后定义您的IUserStore implementation。您必须实施的主要方法是CreateAsync

public System.Threading.Tasks.Task CreateAsync(User user)
{
    // Saves the user in your storage.
    return Task.FromResult(user);
}

它将收到IUser,您必须将其保留在自定义存储空间中并将其返回。

如果您查看我implemented的代码,您可以看到我使用了一些接口IUserRoleStoreIUserPasswordStoreIUserClaimStore等等。需要使用角色和声明。

我还实施了own SignInManager

一旦定义了所有实现,您就可以在startup处引导所有内容:

app.CreatePerOwinContext<Custom.Identity.UserManager>(() => new Custom.Identity.UserManager(new Custom.Identity.UserStore(folderStorage)));
app.CreatePerOwinContext<Custom.Identity.RoleManager>(() => new Custom.Identity.RoleManager(new Custom.Identity.RoleStore(folderStorage)));
app.CreatePerOwinContext<Custom.Identity.SignInService>((options, context) => new Custom.Identity.SignInService(context.GetUserManager<Custom.Identity.UserManager>(), context.Authentication));

您可以查看我尝试验证用户的AccountController

var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
    return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
    return View("Lockout");
case SignInStatus.RequiresVerification:
    return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
case SignInStatus.Failure:
default:
    ModelState.AddModelError("", "Invalid login attempt.");
    return View(model);
}

调用PasswordSignInAsync后,您会注意到UserManager的一些方法会被调用。第一个是FindByNameAsync

public System.Threading.Tasks.Task<User> FindByNameAsync(string userName)
{
    //Fetch your user using the username.
    return Task.FromResult(user);
}

我猜你必须实现你的存储过程,你将从数据库中获取用户。

然后另一种方法FindByIdAsync将是called

public System.Threading.Tasks.Task<User> FindByIdAsync(int userId)
{
    // Fetch - again - your user from the DB with the Id.
    return Task.FromResult(user);
}

您必须再次使用存储过程通过他/她的ID查找您的用户。

如果你从github下载我的项目并玩它,你会发现大多数这些方法都会被多次调用。不要害怕。它就是这样儿的。

我建议你在UserStore的每个方法中插入断点,看看一切是如何组合在一起的。

答案 1 :(得分:4)

您必须实现IUserStore接口。请参阅this article以了解如何为ASP.NET身份实现自定义存储提供程序。

答案 2 :(得分:2)

您还可以覆盖UserManager班级中的方法(例如ApplicationUserManager)来管理授权。以下是使用自定义UserManager.FindAsync逻辑的示例。 UserManager类在身份验证期间由ApplicationOAuthProvider类使用。

public class ApplicationUserManager : UserManager<ApplicationUser>
{
    public ApplicationUserManager() : base(new EmptyUserStore()) { }

    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
    {
        return new ApplicationUserManager();
    }

    public override Task<ApplicationUser> FindAsync(string userName, string password)
    {
        // Authentication logic here.
        throw new NotImplementedException("Authenticate userName and password");

        var result = new ApplicationUser { UserName = userName };
        return Task.FromResult(result);
    }
}

/// <summary>
/// User Store with no implementation. Required for UserManager.
/// </summary>
internal class EmptyUserStore : IUserStore<ApplicationUser>
{
    public Task CreateAsync(ApplicationUser user)
    {
        throw new NotImplementedException();
    }

    public Task DeleteAsync(ApplicationUser user)
    {
        throw new NotImplementedException();
    }

    public Task<ApplicationUser> FindByIdAsync(string userId)
    {
        throw new NotImplementedException();
    }

    public Task<ApplicationUser> FindByNameAsync(string userName)
    {
        throw new NotImplementedException();
    }

    public Task UpdateAsync(ApplicationUser user)
    {
        throw new NotImplementedException();
    }

    public void Dispose()
    {
        // throw new NotImplementedException();
    }
}

请注意,此实现不使用IUserStore接口的好处。