Dodawanie uwierzytelniania tożsamości ASP.NET MVC5 do istniejącego projektu


164

Widziałem wiele podobnych stron w sieci, ale większość z nich korzysta z nowego projektu zamiast istniejącego lub nie ma niezbędnych funkcji. Mam więc istniejący MVC 5projekt i chcę zintegrować tożsamość ASP.NET MVC5 z funkcjami logowania, potwierdzania wiadomości e-mail i resetowania hasła .

Oprócz tego potrzebuję również stworzyć wszystkie niezbędne tabele w bazie danych tj. User, Roles, groups, etc. (używam EF Code First w moim projekcie). Czy istnieje artykuł lub próbka, która odpowiada tym potrzebom? Wszelkie sugestie będą mile widziane. Z góry dziękuję...


Co za wspaniały queston i co za proste rozwiązanie podane poniżej. Uwielbiałem to czytać i bardzo potrzebowałem zintegrować go z moim istniejącym projektem.
Ishwor Khanal

Odpowiedzi:


282

Skonfigurowanie tożsamości do istniejącego projektu nie jest trudne. Musisz zainstalować pakiet NuGet i wykonać niewielką konfigurację.

Najpierw zainstaluj te pakiety NuGet za pomocą konsoli Menedżera pakietów:

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

Dodaj klasę użytkownika i IdentityUserdziedziczenie:

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

Zrób to samo dla roli:

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

Zmień DbContextrodzica z DbContextna IdentityDbContext<AppUser>taki:

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

Jeśli używasz tych samych parametrów połączenia i włączonej migracji, program EF utworzy dla Ciebie niezbędne tabele.

Opcjonalnie możesz rozszerzyć, UserManageraby dodać żądaną konfigurację i dostosowanie:

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

Ponieważ tożsamość jest oparta na OWIN, musisz również skonfigurować OWIN:

Dodaj zajęcia do App_Startfolderu (lub w dowolnym innym miejscu, jeśli chcesz). Ta klasa jest używana przez OWIN. To będzie Twoja klasa startowa.

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

Prawie gotowe, po prostu dodaj tę linię kodu do web.configpliku, aby OWIN mógł znaleźć twoją klasę startową.

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

Teraz w całym projekcie możesz używać Identity tak, jak każdego nowego projektu, który został już zainstalowany przez VS. Rozważmy na przykład akcję logowania

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

Możesz tworzyć role i dodawać do użytkowników:

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

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

Możesz również dodać rolę do użytkownika, na przykład:

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

Używając Authorizemożesz chronić swoje akcje lub kontrolery:

[Authorize]
public ActionResult MySecretAction() {}

lub

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

Możesz także zainstalować dodatkowe pakiety i skonfigurować je tak, aby spełniały Twoje wymagania, takie jak Microsoft.Owin.Security.Facebooklub cokolwiek chcesz.

Uwaga: nie zapomnij dodać odpowiednich przestrzeni nazw do swoich plików:

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;

Możesz także zobaczyć moje inne odpowiedzi, takie jak ta i ta, dotyczące zaawansowanego wykorzystania tożsamości.


2
Oba rozwiązania wyglądają podobnie. AppRoleDo klasyfikacji użytkownika użyłem i menedżera ról tożsamości. A ponieważ Roles i RoleManagerzostały już zaimplementowane przez samą tożsamość, nie musisz przepisywać już zaimplementowanego kodu. Zaktualizuję wpis, aby pokazać, jak możesz używać ról. Jak powiedziałem wcześniej, wystarczy dodać AppUseri AppRolejednostki, aby zainicjować tożsamość. Dziedzicząc swoją DbContextze IdentityDbContext<AppUser>wszystkich niezbędnych tabel, dodaj swoją tabelę. Nie musisz nic robić, wystarczy włączyć migrację.
Sam Farajpour Ghamari

2
Właśnie dodałem przykładowe użycie. Zainstaluj Microsoft.AspNet.Identity.EntityFrameworkw swojej domenie i innych dla interfejsu użytkownika.
Sam Farajpour Ghamari

2
1) Nie martw się o swój web.config. Nie wymieniaj starego. Przeczytaj to, aby uzyskać więcej informacji . Myślę, że twój MVC również został ulepszony.
Sam Farajpour Ghamari

1
2) Dobrze zrobiłeś. 3) nie ma problemu. Będziesz mieć 5 nowych stolików AspNetRoles AspNetUserClaims AspNetUserLogins AspNetUserRolesiAspNetUsers
Sam Farajpour Ghamari

3
Właśnie przeczytałem wszystkie komentarze, które zostawiłeś, pomagając Clintowi Eastwoodowi, Niezła robota !! Świat potrzebuje więcej ludzi takich jak Ty plusOne
Chef_Code

24

Oto, co zrobiłem, aby zintegrować Identity z istniejącą bazą danych.

  1. Utwórz przykładowy projekt MVC za pomocą szablonu MVC. Zawiera cały kod potrzebny do implementacji tożsamości - Startup.Auth.cs, IdentityConfig.cs, kod kontrolera konta, zarządzanie kontrolerem, modele i powiązane widoki.

  2. Zainstaluj niezbędne pakiety NuGet dla tożsamości i OWIN. Pojawi się pomysł, widząc odniesienia w przykładowym projekcie i odpowiedź od @Sam

  3. Skopiuj cały ten kod do istniejącego projektu. Pamiętaj, nie zapomnij dodać parametrów połączenia „DefaultConnection”, aby tożsamość była mapowana do Twojej bazy danych. Sprawdź klasę ApplicationDBContext w IdentityModel.cs, w której znajdziesz odniesienie do parametrów połączenia „DefaultConnection”.

  4. Oto skrypt SQL, który uruchomiłem w mojej istniejącej bazie danych, aby utworzyć niezbędne tabele:

    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. Sprawdź i rozwiąż wszystkie pozostałe błędy i gotowe. Tożsamość zajmie się resztą :)


1
Wielkie dzięki za odpowiedź i miłe wyjaśnienia. Właściwie myślę o zastosowaniu innego podejścia, ale też spróbuję. Zagłosowano +
Jack

2
Myślę, że jest to znacznie czystsze podejście
niico

3
Oprócz klasy Startup.Auth.cs musisz skopiować plik Startup.cs znajdujący się w katalogu głównym przykładowego projektu.
Padmika,

Shyamal, czy możesz dodać Startup.cs z komentarza @ Padmika? To jest ważne.
Mike

4

Polecam IdentityServer. To jest .NET Foundation projekt i obejmuje wiele zagadnień związanych z uwierzytelnianiem i autoryzacją.

Przegląd

IdentityServer to platforma oparta na platformie .NET / Katana i hostowany składnik, który umożliwia wdrażanie pojedynczego logowania i kontroli dostępu do nowoczesnych aplikacji internetowych i interfejsów API przy użyciu protokołów, takich jak OpenID Connect i OAuth2. Obsługuje szeroką gamę klientów, takich jak aplikacje mobilne, internetowe, SPA i aplikacje desktopowe, i jest rozszerzalny, aby umożliwić integrację z nowymi i istniejącymi architekturami.

Aby uzyskać więcej informacji, np

  • obsługa sklepów użytkowników opartych na MembershipReboot i ASP.NET Identity
  • obsługa dodatkowego oprogramowania pośredniczącego uwierzytelniania Katana (np. Google, Twitter, Facebook itp.)
  • wsparcie dla trwałości konfiguracji opartej na EntityFramework
  • wsparcie dla WS-Federation
  • rozciągliwość

sprawdź dokumentację i demo .


6
Przed ślepym przejściem do implementacji IdentityServer należy rozważyć praktyczne zastosowania IdentityServer.
hanzolo
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.