Customizing Individual User Accounts

Asked

Viewed 541 times

1

Well, I have an Asp.Net MVC web project that uses Individual User Accounts and I would like to use a specific table in my database and a different class to manage user login. How can I do this?

1 answer

2


First of all, it is important to read this answer so that we have a starting point.

For the purpose of this response, I have managed a new project with Individual User Accounts. It’s a good starting point for the tailor shop.

As a "zero step", I suggest creating the following directory structure in your project:

Infrastructure

Step 1: Creating your Models

The project is already configured with a context ready for the Entity Framework and some Models, as well as a connection to a base Localdb. You can insert your new Models in the existing context or create another.

For example, I will do everything in a separate context, precisely to achieve the didactic objective of the answer.

I created a separate context, in Models:

namespace CustomIndividualUserAccounts.Models
{
    public class CustomContext : DbContext
    {
        public CustomContext() : base("name=DefaultConnection") { }
    }
}

Enable a configuration of Migrations for this new context. I open the Package Manager Console (View > Other Windows > Package Manager Console) and type:

PM> Enable-Migrations -ContextTypeName CustomIndividualUserAccounts.Models.CustomContext
Checking if the context targets an existing database...
Code First Migrations enabled for project CustomIndividualUserAccounts.

If you don’t know Migrations, see this link.

I create a class Usuario:

namespace CustomIndividualUserAccounts.Models
{
    [DisplayColumn("Nome")]
    public class Usuario
    {
        [Key]
        public Guid UsuarioId { get; set; }
        [Required]
        public String Nome { get; set; }
        [DataType(DataType.Password)]
        public String Senha { get; set; }
    }
}

A class Perfil:

namespace CustomIndividualUserAccounts.Models
{
    [DisplayColumn("Nome")]
    public class Perfil
    {
        [Key]
        public Guid PerfilId { get; set; }
        [Required]
        public String Nome { get; set; }
    }
}

And a class UsuarioPerfil:

namespace CustomIndividualUserAccounts.Models
{
    public class UsuarioPerfil
    {
        [Key]
        public Guid UsuarioPerfilId { get; set; }
        public Guid UsuarioId { get; set; }
        public Guid PerfilId { get; set; }

        public virtual Usuario Usuario { get; set; }
        public virtual Perfil Perfil { get; set; }
    }
}

Optionally, you can put the table navigation properties UsuarioPerfil in Usuario and in Perfil:

[DisplayColumn("Nome")]
public class Usuario
{
    [Key]
    public Guid UsuarioId { get; set; }
    [Required]
    public String Nome { get; set; }
    [DataType(DataType.Password)]
    public String Senha { get; set; }

    public virtual ICollection<UsuarioPerfil> UsuarioPerfis { get; set; }
}

[DisplayColumn("Nome")]
public class Perfil
{
    [Key]
    public Guid PerfilId { get; set; }
    [Required]
    public String Nome { get; set; }

    public virtual ICollection<UsuarioPerfil> UsuarioPerfis { get; set; }
}

Add 3 DbSet<> in the context:

namespace CustomIndividualUserAccounts.Models
{
    public class CustomContext : DbContext
    {
        public CustomContext() : base("name=DefaultConnection") { }

        public DbSet<Usuario> Usuarios { get; set; }
        public DbSet<Perfil> Perfis { get; set; }
        public DbSet<UsuarioPerfil> UsuariosPerfis { get; set; }
    }
}

Create a Migration for them and update the database by Package Manager Console:

PM> Add-Migration Inicial
Scaffolding migration 'Inicial'.
The Designer Code for this migration file includes a snapshot of your current Code First model. This snapshot is used to calculate the changes to your model when you scaffold the next migration. If you make additional changes to your model that you want to include in this migration, then you can re-scaffold it by running 'Add-Migration Inicial' again.
PM> Update-Database
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
Applying explicit migrations: [201506031521384_Inicial].
Applying explicit migration: 201506031521384_Inicial.
Running Seed method.

Step 2: Exchanging UserManager

In Infrastructure\Authentication, create a class called CustomUserManager and make it derive from UserManager, passing my user as required generic type:

namespace CustomIndividualUserAccounts.Infrastructure.Authentication
{
    public class CustomUserManager : UserManager<Usuario>
    {
    }
}

Here possibly Visual Studio will claim that Usuario does not implement IUser<>. We can adjust the class Usuario without the need to generate Migrations additional. Mine looked like this:

namespace CustomIndividualUserAccounts.Models
{
    [DisplayColumn("Nome")]
    public class Usuario : Microsoft.AspNet.Identity.IUser<String>
    {
        [Key]
        public Guid UsuarioId { get; set; }
        [Required]
        public String Nome { get; set; }
        [DataType(DataType.Password)]
        public String Senha { get; set; }

        public virtual ICollection<UsuarioPerfil> UsuarioPerfis { get; set; }

        public string Id
        {
            get { return UsuarioId.ToString(); }
        }

        public string UserName
        {
            get
            {
                return Nome;
            }
            set
            {
                Nome = value;
            }
        }
    }
}

There are several things that can be adjusted here. See the implementation of ApplicationUserManager in App_Start\IdentityConfig.cs for examples of what can be configured.

Step 3: Exchanging SignInManager

SignInManager is the class responsible for authentication. It is referenced in Controllers\AccountController.cs and its derived implementation is in App_Start\IdentityConfig.cs (class ApplicationSignInManager).

Here I will create my implementation of SignInManager.

namespace CustomIndividualUserAccounts.Infrastructure.Authentication
{
    public class CustomSignInManager : SignInManager<Usuario, string>
    {
    }
}

Step 4: Reimplementing Methods

Here is a particular step. Each implementation has its own set of differences from native ASP.NET Identity. What I can provide are examples of what can be reimplemented, so that this answer is not too extensive.

The example below I reimplemento the authentication itself:

using CustomIndividualUserAccounts.Models;
using Microsoft.AspNet.Identity.Owin;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using System.Data.Entity;

namespace CustomIndividualUserAccounts.Infrastructure.Authentication
{
    public class CustomSignInManager : SignInManager<Usuario, string>
    {
        public CustomContext contexto = new CustomContext();

        public override async Task<SignInStatus> PasswordSignInAsync(string userName, string password, bool isPersistent, bool shouldLockout)
        {
            var usuario = await contexto.Usuarios.FirstOrDefaultAsync(u => u.Nome == userName);
            if (usuario == null) return SignInStatus.Failure;

            if (usuario.Senha != password) return SignInStatus.Failure;

            return SignInStatus.Success;
        }
    }
}

Notice I’ve taken a lot of teaching liberties. Not by far this procedure is safe, the password is not encrypted, etc, etc, etc. The goal is only demonstrative.

Try to read a lot of code from the original implementations. SignInManager is here. UserManager, here.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.