【问题标题】:Implementing UserManager to use a custom class and Stored Procedures实现 UserManager 以使用自定义类和存储过程
【发布时间】:2015-06-14 02:53:04
【问题描述】:

我的应用程序的所有身份验证和授权过程都是使用存储过程完成的。我编写了一个包含我需要的所有功能的类,例如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;
    }
}

【问题讨论】:

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


    【解决方案1】:

    正如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,
            };
        }
    }
    

    然后定义你的IUserStoreimplementation。你必须实现的主要方法是CreateAsync

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

    它将收到一个IUser,您必须将其保存在您的自定义存储中并返回。

    如果您查看我的代码 implemented,您会发现我使用了一些接口 IUserRoleStoreIUserPasswordStoreIUserClaimStore 等,因为我需要使用角色和声明。

    我还实现了我的ownSignInManager

    一旦您定义了所有实现,您就可以在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 的每个方法中都插入断点,然后看看它们是如何组合在一起的。

    【讨论】:

    • The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters. 登录并在UserManager.FindAsync 中出现上述错误。任何的想法?我认为它与GetPasswordHashAsync 相关。我该怎么做?
    • 很难说。你试过我的示例项目吗? FindAsync 使用 UserLoginInfo。如果您使用的是外部提供商(谷歌、脸书),它会通过该管道。如果你不使用它,你应该通过那里。如果您使用的是外部提供者,您可以实现 UserLoginInfo 管理器。你可以查看 Raven 的implementation
    • 感谢 Lefty,我已经检查了您的代码。我没有使用外部提供商。而不是使用用户管理器的查找,我使用了我自己的自定义函数来节省一些时间! :)
    • @Akbari:很高兴我能帮上忙。如果您认为我的回答足够好,请您接受吗?干杯。
    • 我已经从您在答案中给出的链接下载了项目,但我被困在这里:app.CreatePerOwinContext(() => new Custom.Identity.UserManager(新的 Custom.Identity.UserStore(folderStorage))); app.CreatePerOwinContext(() => new Custom.Identity.RoleManager(new Custom.Identity.RoleStore(folderStorage)));
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      您还可以覆盖 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 接口的好处。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-10-23
        • 2011-05-05
        • 2015-04-11
        • 1970-01-01
        • 1970-01-01
        • 2019-12-14
        • 2017-10-06
        • 1970-01-01
        相关资源
        最近更新 更多