191

I have seen lots of similar pages on the web, but most of them use a new project instead of an existing one, or don't have the necessary features. So, I have an existing MVC 5 project and want to integrate ASP.NET MVC5 Identity with log in, email confirmation and password reset features.

In addition, I also need to create all the necessary tables on the database i.e. Users, Roles, groups, etc. (I have used EF Code-First in my project). Is there an article or sample that corresponds to these needs?

1
  • 1
    What a great queston and what a simple solutin given just below. I loved it to read through and badly needed to integrate in my existing project too. Commented Oct 30, 2018 at 11:35

4 Answers 4

313

Configuring Identity to your existing project is not hard thing. You must install some NuGet package and do some small configuration.

First install these NuGet packages with Package Manager Console:

PM> Install-Package Microsoft.AspNet.Identity.Owin 
PM> Install-Package Microsoft.AspNet.Identity.EntityFramework
PM> Install-Package Microsoft.Owin.Host.SystemWeb 

Add a user class and with IdentityUser inheritance:

public class AppUser : IdentityUser
{
    //add your custom properties which have not included in IdentityUser before
    public string MyExtraProperty { get; set; }  
}

Do same thing for role:

public class AppRole : IdentityRole
{
    public AppRole() : base() { }
    public AppRole(string name) : base(name) { }
    // extra properties here 
}

Change your DbContext parent from DbContext to IdentityDbContext<AppUser> like this:

public class MyDbContext : IdentityDbContext<AppUser>
{
    // Other part of codes still same 
    // You don't need to add AppUser and AppRole 
    // since automatically added by inheriting form IdentityDbContext<AppUser>
}

If you use the same connection string and enabled migration, EF will create necessary tables for you.

Optionally, you could extend UserManager to add your desired configuration and customization:

public class AppUserManager : UserManager<AppUser>
{
    public AppUserManager(IUserStore<AppUser> store)
        : base(store)
    {
    }

    // this method is called by Owin therefore this is the best place to configure your User Manager
    public static AppUserManager Create(
        IdentityFactoryOptions<AppUserManager> options, IOwinContext context)
    {
        var manager = new AppUserManager(
            new UserStore<AppUser>(context.Get<MyDbContext>()));

        // optionally configure your manager
        // ...

        return manager;
    }
}

Since Identity is based on OWIN you need to configure OWIN too:

Add a class to App_Start folder (or anywhere else if you want). This class is used by OWIN. This will be your startup class.

namespace MyAppNamespace
{
    public class IdentityConfig
    {
        public void Configuration(IAppBuilder app)
        {
            app.CreatePerOwinContext(() => new MyDbContext());
            app.CreatePerOwinContext<AppUserManager>(AppUserManager.Create);
            app.CreatePerOwinContext<RoleManager<AppRole>>((options, context) =>
                new RoleManager<AppRole>(
                    new RoleStore<AppRole>(context.Get<MyDbContext>())));

            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Home/Login"),
            });
        }
    }
}

Almost done just add this line of code to your web.config file so OWIN could find your startup class.

<appSettings>
    <!-- other setting here -->
    <add key="owin:AppStartup" value="MyAppNamespace.IdentityConfig" />
</appSettings>

Now in entire project you could use Identity just like any new project had already installed by VS. Consider login action for example

[HttpPost]
public ActionResult Login(LoginViewModel login)
{
    if (ModelState.IsValid)
    {
        var userManager = HttpContext.GetOwinContext().GetUserManager<AppUserManager>();
        var authManager = HttpContext.GetOwinContext().Authentication;

        AppUser user = userManager.Find(login.UserName, login.Password);
        if (user != null)
        {
            var ident = userManager.CreateIdentity(user, 
                DefaultAuthenticationTypes.ApplicationCookie);
            //use the instance that has been created. 
            authManager.SignIn(
                new AuthenticationProperties { IsPersistent = false }, ident);
            return Redirect(login.ReturnUrl ?? Url.Action("Index", "Home"));
        }
    }
    ModelState.AddModelError("", "Invalid username or password");
    return View(login);
}

You could make roles and add to your users:

public ActionResult CreateRole(string roleName)
{
    var roleManager=HttpContext.GetOwinContext().GetUserManager<RoleManager<AppRole>>();

    if (!roleManager.RoleExists(roleName))
        roleManager.Create(new AppRole(roleName));
    // rest of code
} 

You could also add a role to a user, like this:

UserManager.AddToRole(UserManager.FindByName("username").Id, "roleName");

By using Authorize you could guard your actions or controllers:

[Authorize]
public ActionResult MySecretAction() {}

or

[Authorize(Roles = "Admin")]]
public ActionResult MySecretAction() {}

You can also install additional packages and configure them to meet your requirement like Microsoft.Owin.Security.Facebook or whichever you want.

Note: Don't forget to add relevant namespaces to your files:

using Microsoft.AspNet.Identity;
using Microsoft.Owin.Security;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Owin;

You could also see my other answers like this and this for advanced use of Identity.

29
  • 2
    Both solutions look similar. I have used AppRole and Identity's role manager to classify user. And since Roles and RoleManager have already implemented by Identity itself you don't need rewrite already implemented code. I will update the post to show you how you can use roles. And as I said before you just need add AppUser and AppRole entities to initialize Identity. By inheriting your DbContext from IdentityDbContext<AppUser> all necessary tables add your table. You don't need do anything just enable migration. Commented Aug 12, 2015 at 15:26
  • 2
    I just added some sample usage. Install Microsoft.AspNet.Identity.EntityFramework to your Domain and other for UI. Commented Aug 12, 2015 at 15:56
  • 2
    1) Don't worry about your web.config. Don't replace old one. Read this for more info. I think your MVC also upgraded. Commented Aug 12, 2015 at 17:59
  • 4
    I just read through all the comments you left helping Clint Eastwood, Nice Job!! The world needs more people like You plusOne
    – Chef_Code
    Commented Dec 12, 2016 at 23:45
  • 2
    It almost worked. But I was getting error during migration EntityType 'IdentityUserRole' has no key defined and I solved it by adding base.OnModelCreating(modelBuilder); to the OnModelCreating function. Commented Mar 29, 2019 at 10:31
29

This is what I did to integrate Identity with an existing database.

  1. Create a sample MVC project with MVC template. This has all the code needed for Identity implementation - Startup.Auth.cs, IdentityConfig.cs, Account Controller code, Manage Controller, Models and related views.

  2. Install the necessary nuget packages for Identity and OWIN. You will get an idea by seeing the references in the sample Project and the answer by @Sam

  3. Copy all these code to your existing project. Please note don't forget to add the "DefaultConnection" connection string for Identity to map to your database. Please check the ApplicationDBContext class in IdentityModel.cs where you will find the reference to "DefaultConnection" connection string.

  4. This is the SQL script I ran on my existing database to create necessary tables:

    USE ["YourDatabse"]
    GO
    /****** Object:  Table [dbo].[AspNetRoles]    Script Date: 16-Aug-15 6:52:25 PM ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    CREATE TABLE [dbo].[AspNetRoles](
    [Id] [nvarchar](128) NOT NULL,
    [Name] [nvarchar](256) NOT NULL,
    CONSTRAINT [PK_dbo.AspNetRoles] PRIMARY KEY CLUSTERED 
    (
      [Id] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    
    GO
    /****** Object:  Table [dbo].[AspNetUserClaims]    Script Date: 16-Aug-15 6:52:25 PM ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    CREATE TABLE [dbo].[AspNetUserClaims](
       [Id] [int] IDENTITY(1,1) NOT NULL,
       [UserId] [nvarchar](128) NOT NULL,
       [ClaimType] [nvarchar](max) NULL,
       [ClaimValue] [nvarchar](max) NULL,
    CONSTRAINT [PK_dbo.AspNetUserClaims] PRIMARY KEY CLUSTERED 
    (
       [Id] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
    
    GO
    /****** Object:  Table [dbo].[AspNetUserLogins]    Script Date: 16-Aug-15 6:52:25 PM ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    CREATE TABLE [dbo].[AspNetUserLogins](
        [LoginProvider] [nvarchar](128) NOT NULL,
        [ProviderKey] [nvarchar](128) NOT NULL,
        [UserId] [nvarchar](128) NOT NULL,
    CONSTRAINT [PK_dbo.AspNetUserLogins] PRIMARY KEY CLUSTERED 
    (
        [LoginProvider] ASC,
        [ProviderKey] ASC,
        [UserId] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    
    GO
    /****** Object:  Table [dbo].[AspNetUserRoles]    Script Date: 16-Aug-15 6:52:25 PM ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    CREATE TABLE [dbo].[AspNetUserRoles](
       [UserId] [nvarchar](128) NOT NULL,
       [RoleId] [nvarchar](128) NOT NULL,
    CONSTRAINT [PK_dbo.AspNetUserRoles] PRIMARY KEY CLUSTERED 
    (
        [UserId] ASC,
        [RoleId] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    
    GO
    /****** Object:  Table [dbo].[AspNetUsers]    Script Date: 16-Aug-15 6:52:25 PM ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    CREATE TABLE [dbo].[AspNetUsers](
        [Id] [nvarchar](128) NOT NULL,
        [Email] [nvarchar](256) NULL,
        [EmailConfirmed] [bit] NOT NULL,
        [PasswordHash] [nvarchar](max) NULL,
        [SecurityStamp] [nvarchar](max) NULL,
        [PhoneNumber] [nvarchar](max) NULL,
        [PhoneNumberConfirmed] [bit] NOT NULL,
        [TwoFactorEnabled] [bit] NOT NULL,
        [LockoutEndDateUtc] [datetime] NULL,
        [LockoutEnabled] [bit] NOT NULL,
        [AccessFailedCount] [int] NOT NULL,
        [UserName] [nvarchar](256) NOT NULL,
    CONSTRAINT [PK_dbo.AspNetUsers] PRIMARY KEY CLUSTERED 
    (
        [Id] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
    
     GO
     ALTER TABLE [dbo].[AspNetUserClaims]  WITH CHECK ADD  CONSTRAINT [FK_dbo.AspNetUserClaims_dbo.AspNetUsers_UserId] FOREIGN KEY([UserId])
     REFERENCES [dbo].[AspNetUsers] ([Id])
     ON DELETE CASCADE
     GO
     ALTER TABLE [dbo].[AspNetUserClaims] CHECK CONSTRAINT [FK_dbo.AspNetUserClaims_dbo.AspNetUsers_UserId]
     GO
     ALTER TABLE [dbo].[AspNetUserLogins]  WITH CHECK ADD  CONSTRAINT [FK_dbo.AspNetUserLogins_dbo.AspNetUsers_UserId] FOREIGN KEY([UserId])
     REFERENCES [dbo].[AspNetUsers] ([Id])
     ON DELETE CASCADE
     GO
     ALTER TABLE [dbo].[AspNetUserLogins] CHECK CONSTRAINT [FK_dbo.AspNetUserLogins_dbo.AspNetUsers_UserId]
     GO
     ALTER TABLE [dbo].[AspNetUserRoles]  WITH CHECK ADD  CONSTRAINT [FK_dbo.AspNetUserRoles_dbo.AspNetRoles_RoleId] FOREIGN KEY([RoleId])
     REFERENCES [dbo].[AspNetRoles] ([Id])
     ON DELETE CASCADE
     GO
     ALTER TABLE [dbo].[AspNetUserRoles] CHECK CONSTRAINT [FK_dbo.AspNetUserRoles_dbo.AspNetRoles_RoleId]
     GO
     ALTER TABLE [dbo].[AspNetUserRoles]  WITH CHECK ADD  CONSTRAINT [FK_dbo.AspNetUserRoles_dbo.AspNetUsers_UserId] FOREIGN KEY([UserId])
     REFERENCES [dbo].[AspNetUsers] ([Id])
     ON DELETE CASCADE
     GO
     ALTER TABLE [dbo].[AspNetUserRoles] CHECK CONSTRAINT [FK_dbo.AspNetUserRoles_dbo.AspNetUsers_UserId]
     GO
    
  5. Check and solve any remaining errors and you are done. Identity will handle the rest :)

4
  • 2
    Many thanks for your reply and nice explanations. Actually I think of using another approach, but I will also try it. Voted+
    – Jack
    Commented Aug 18, 2015 at 12:42
  • 4
    I think this is a much cleaner approach
    – niico
    Commented Nov 13, 2017 at 17:01
  • 5
    In addition to the Startup.Auth.cs class you need to copy the Startup.cs located at the root of the sample project.
    – Padmika
    Commented Nov 18, 2017 at 10:56
  • 2
    Shyamal can you add the Startup.cs from @Padmika's comment? This is important.
    – Mike
    Commented Feb 19, 2020 at 14:03
4

I recommend IdentityServer.This is a .NET Foundation project and covers many issues about authentication and authorization.

Overview

IdentityServer is a .NET/Katana-based framework and hostable component that allows implementing single sign-on and access control for modern web applications and APIs using protocols like OpenID Connect and OAuth2. It supports a wide range of clients like mobile, web, SPAs and desktop applications and is extensible to allow integration in new and existing architectures.

For more information, e.g.

  • support for MembershipReboot and ASP.NET Identity based user stores
  • support for additional Katana authentication middleware (e.g. Google, Twitter, Facebook etc)
  • support for EntityFramework based persistence of configuration
  • support for WS-Federation
  • extensibility

check out the documentation and the demo.

1
  • 6
    The practical usages of IdentityServer should be considered before blindly jumping into an IdentityServer implementation.
    – hanzolo
    Commented Jan 12, 2018 at 21:20
1

well, I know I am probably too late. This is for those who already did one or many migration. those that there project works perfectly, those who have the AspNet tables in there database , but don't have controllers, models and view related to those.
I also cam across the same issue. I started my project without activating the authentication at the beginning. Then I realized I did no have all the element for the authentication(Account and Manage in the Views folder, accountController and ManageControler in the controller, and AccountViewModel and ManageViewModel in the Model). I just created and other project with similar settings, name and I activated the authentication at the creation of that project. then I manage to copie the missing file to my initial project. After that, I went through each of then to change the namespaces and imports to the namespace of my project

0

Not the answer you're looking for? Browse other questions tagged or ask your own question.