Adicionando autenticação de identidade do ASP.NET MVC5 a um projeto existente

164

Eu já vi muitas páginas semelhantes na Web, mas a maioria delas usa um novo projeto em vez de um existente ou não possui os recursos necessários. Portanto, eu tenho um MVC 5projeto existente e quero integrar o ASP.NET MVC5 Identity aos recursos de login, confirmação por email e redefinição de senha .

Além disso, também preciso criar todas as tabelas necessárias no banco de dados, como Usuário, Funções, grupos etc. (uso o Código EF Primeiro no meu projeto). Existe um artigo ou amostra que corresponde a essas necessidades? Qualquer sugestão será apreciada. Desde já, obrigado...

Jack
fonte
Que grande missão e que solução simples dada logo abaixo. Adorei ler e precisava muito integrar-me também ao meu projeto existente.
Ishwor Khanal

Respostas:

282

Configurar a identidade para o seu projeto existente não é algo difícil. Você deve instalar algum pacote NuGet e fazer algumas pequenas configurações.

Primeiro instale estes pacotes NuGet com o Package Manager Console:

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

Adicione uma classe de usuário e com IdentityUserherança:

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

Faça o mesmo para a função:

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

Mude seu DbContextpai de DbContextpara IdentityDbContext<AppUser>assim:

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

Se você usar a mesma cadeia de conexão e a migração ativada, o EF criará as tabelas necessárias para você.

Opcionalmente, você pode estender UserManagerpara adicionar sua configuração e customização desejadas:

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

Como o Identity é baseado no OWIN, você também precisa configurar o OWIN:

Adicione uma classe à App_Startpasta (ou a qualquer outro lugar, se desejar). Esta classe é usada pelo OWIN. Esta será sua classe de inicialização.

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

Quase pronto, basta adicionar esta linha de código ao seu web.configarquivo para que o OWIN possa encontrar sua classe de inicialização.

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

Agora, em todo o projeto, você pode usar o Identity, como qualquer novo projeto já instalado pelo VS. Considere a ação de login, por exemplo

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

Você pode criar funções e adicionar aos seus usuários:

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

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

Você também pode adicionar uma função a um usuário, assim:

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

Ao usar, Authorizevocê pode proteger suas ações ou controladores:

[Authorize]
public ActionResult MySecretAction() {}

ou

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

Você também pode instalar pacotes adicionais e configurá-los para atender aos seus requisitos, como Microsoft.Owin.Security.Facebookou o que você quiser.

Nota: Não esqueça de adicionar espaços de nome relevantes aos seus arquivos:

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;

Você também pode ver minhas outras respostas como esta e esta para uso avançado da identidade.

Sam Farajpour Ghamari
fonte
2
Ambas as soluções parecem semelhantes. Eu usei AppRoleo gerenciador de funções do Identity para classificar o usuário. E uma vez que Roles e RoleManagerjá implementados pela própria identidade você não precisa reescrever o código já implementadas. Vou atualizar a postagem para mostrar como você pode usar funções. E como eu disse antes, você só precisa adicionar entidades AppUsere AppRolepara inicializar a Identidade. Ao herdar o seu DbContextde IdentityDbContext<AppUser>todas as tabelas necessárias, adicione sua tabela. Você não precisa fazer nada, apenas ativar a migração.
Sam Farajpour Ghamari
2
Acabei de adicionar alguns exemplos de uso. Instale Microsoft.AspNet.Identity.EntityFrameworkno seu domínio e outro para interface do usuário.
Sam Farajpour Ghamari
2
1) Não se preocupe com o seu web.config. Não substitua o antigo. Leia isto para mais informações . Eu acho que seu MVC também atualizou.
Sam Farajpour Ghamari
1
2) Você fez certo. 3) não tem problema. Você terá 5 novas tabelas AspNetRoles AspNetUserClaims AspNetUserLogins AspNetUserRoleseAspNetUsers
Sam Farajpour Ghamari 12/08/2015
3
Acabei de ler todos os comentários que você deixou para ajudar Clint Eastwood, Nice Job !! O mundo precisa de mais pessoas como Você plusOne
Chef_Code 12/12
24

Foi o que fiz para integrar o Identity a um banco de dados existente.

  1. Crie um projeto MVC de amostra com o modelo MVC. Este possui todo o código necessário para a implementação do Identity - Startup.Auth.cs, IdentityConfig.cs, código do Account Controller, Manage Controller, Models e visualizações relacionadas.

  2. Instale os pacotes de nuget necessários para Identity e OWIN. Você terá uma idéia vendo as referências no projeto de amostra e a resposta em @Sam

  3. Copie todos esses códigos para o seu projeto existente. Observe que não se esqueça de adicionar a cadeia de conexão "DefaultConnection" para o Identity mapear no seu banco de dados. Verifique a classe ApplicationDBContext em IdentityModel.cs, onde você encontrará a referência à cadeia de conexão "DefaultConnection".

  4. Este é o script SQL que executei no meu banco de dados existente para criar as tabelas necessárias:

    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. Verifique e solucione os erros restantes e pronto. Identidade vai lidar com o resto :)

Shyamal Parikh
fonte
1
Muito obrigado pela sua resposta e boas explicações. Na verdade, penso em usar outra abordagem, mas também tentarei. Votado +
Jack
2
Eu acho que esta é uma abordagem mais limpo muito
niico
3
Além da classe Startup.Auth.cs, você precisa copiar o Startup.cs localizado na raiz do projeto de amostra.
Padmika
Shyamal, você pode adicionar o Startup.cs no comentário de @ Padmika? Isso é importante.
Mike
4

Eu recomendo o IdentityServer . Este é um projeto do .NET Foundation e cobre muitos problemas sobre autenticação e autorização.

Visão geral

O IdentityServer é uma estrutura baseada em .NET / Katana e um componente host que permite implementar o logon único e o controle de acesso para aplicativos da Web modernos e APIs usando protocolos como o OpenID Connect e o OAuth2. Ele suporta uma ampla variedade de clientes, como móveis, web, SPAs e aplicativos de desktop, e é extensível para permitir a integração em arquiteturas novas e existentes.

Para mais informações, por exemplo

  • suporte para armazenamentos de usuários MembershipReboot e ASP.NET Identity
  • suporte para middleware de autenticação Katana adicional (por exemplo, Google, Twitter, Facebook etc.)
  • suporte para persistência de configuração baseada em EntityFramework
  • suporte para Federação WS
  • extensibilidade

confira a documentação e a demonstração .

TotPeRo
fonte
6
Os usos práticos do IdentityServer devem ser considerados antes de pular cegamente para uma implementação do IdentityServer.
hanzolo