Implementing a UserManager to Use a Custom Class and Stored Procedures

The entire authentication and authorization process of my application is performed using stored procedures. I wrote a class with all the functionality I need, for example. GetUsers , Login , AddRole , AddMember , etc. An administration page is also used to manage users, roles, and permissions using this class.

I just need to add authentication (I mean the authorize attribute), cookies for logging in and out, and storing some server data for each login. I think I need to implement Identity for this?

In this case, can you direct me with its implementation? It seems that the most basic thing you need to do is implement the create method, which passes the IUserStore instance to the constructor. But I do not need to have tables for users or roles, how can I implement this method?

This is the current class, and please let me know if you need to see my own authentication class that uses stored procedures.

 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; } } 
+5
source share
3 answers

As alisabzevari, you suggested implementing IUserStore . <sh> You do not even depend on the structure of the storage and the table. You can customize every bit of your storage level.

I did some experimentation and tried to implement my own UserManager and RoleManager using another repository like Biggy

File-based document repository for .NET.

Here you can find the code here on GitHub.

The first thing to do is to implement the UserManager , where you can configure the requirements for password verification:

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

and then define the implementation of IUserStore . The main method you should implement is CreateAsync :

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

he will receive the IUser , which you must save in your specialized repository and return it.

If you look at the code that I used , you can see that I used several interfaces IUserRoleStore , IUserPasswordStore , IUserClaimStore , etc. etc., since I needed to use roles and claims.

I also implemented my own SignInManager .

Once you have defined your entire implementation, you can load everything into 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)); 

You can check the AccountController where I try to check the user:

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

After calling PasswordSignInAsync you will notice that some of the methods of your UserManager will be called. The first will be FindByNameAsync :

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

You will need to implement your stored procedure, I think, where will you select your user from the database.

Then another FindByIdAsync method will be called :

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

Again, you will have to use the stored procedure to find your user by his / her identifier.

If you download my project from github and play with it, you will notice that most of these methods will be called multiple times. Do not be afraid. The way it is.

I would suggest that you insert breakpoints in each UserStore method and see how everything fits together.

+7
source

You need to implement the IUserStore interface. See this article to learn how to implement custom storage providers for ASP.NET authentication.

+4
source

You can also override methods in the UserManager class (for example, ApplicationUserManager ) to control authorization. Here is an example that uses the user logic UserManager.FindAsync . The UserManager class is used by the ApplicationOAuthProvider class during authentication.

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

Please note that this implementation does not take advantage of the IUserStore interface.

+1
source

All Articles