将 ASP.NET MVC5 身份验证添加到现有项目

Posted

技术标签:

【中文标题】将 ASP.NET MVC5 身份验证添加到现有项目【英文标题】:Adding ASP.NET MVC5 Identity Authentication to an existing project 【发布时间】:2015-11-04 18:43:36 【问题描述】:

我在网上看到过很多类似的页面,但大多数都使用新项目而不是现有项目,或者没有必要的功能。因此,我有一个现有的 MVC 5 项目,并希望将 ASP.NET MVC5 Identity 与登录、电子邮件确认和密码重置功能集成。

除此之外,我还需要在数据库上创建所有必要的表,即用户、角色、组等(我在项目中使用 EF Code First)。有没有符合这些需求的文章或样本?

【问题讨论】:

这是一个多么棒的问题,下面给出了多么简单的解决方案。我喜欢它通读,也非常需要集成到我现有的项目中。 【参考方案1】:

为现有项目配置身份并不难。您必须安装一些 NuGet 包并进行一些小配置。

首先使用包管理器控制台安装这些 NuGet 包:

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

添加一个用户类和IdentityUser继承:

public class AppUser : IdentityUser

    //add your custom properties which have not included in IdentityUser before
    public string MyExtraProperty  get; set;   

为角色做同样的事情:

public class AppRole : IdentityRole

    public AppRole() : base()  
    public AppRole(string name) : base(name)  
    // extra properties here 

将您的 DbContext 父级从 DbContext 更改为 IdentityDbContext<AppUser>,如下所示:

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>

如果您使用相同的连接字符串并启用迁移,EF 将为您创建必要的表。

或者,您可以扩展 UserManager 以添加您想要的配置和自定义:

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;
    

由于 Identity 是基于 OWIN 的,所以你也需要配置 OWIN:

将类添加到App_Start 文件夹(或其他任何地方,如果您愿意)。此类由 OWIN 使用。这将是你的创业课程。

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

几乎完成了,只需将这行代码添加到您的web.config 文件中,以便 OWIN 可以找到您的启动类。

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

现在在整个项目中,您可以像使用 VS 已安装的任何新项目一样使用 Identity。以登录操作为例

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

您可以创建角色并添加到您的用户:

public ActionResult CreateRole(string roleName)

    var roleManager=HttpContext.GetOwinContext().GetUserManager<RoleManager<AppRole>>();

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

您还可以向用户添加角色,如下所示:

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

通过使用Authorize,您可以保护您的操作或控制器:

[Authorize]
public ActionResult MySecretAction() 

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

您还可以安装其他软件包并对其进行配置以满足您的要求,例如 Microsoft.Owin.Security.Facebook 或任何您想要的。

注意:不要忘记将相关的命名空间添加到您的文件中:

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;

您还可以查看我的其他答案,例如 this 和 this 以了解身份的高级使用。

【讨论】:

两种解决方案看起来相似。我使用AppRole 和Identity 的角色管理器对用户进行分类。由于 Roles 和 RoleManager 已经由 Identity 本身实现,您不需要重写已经实现的代码。我将更新帖子以向您展示如何使用角色。正如我之前所说,您只需要添加AppUserAppRole 实体来初始化身份。通过从IdentityDbContext&lt;AppUser&gt; 继承您的DbContext,所有必要的表都可以添加您的表。您无需执行任何操作,只需启用迁移即可。 我刚刚添加了一些示例用法。将Microsoft.AspNet.Identity.EntityFramework 安装到您的域和其他用户界面。 1) 不要担心您的web.config。不要更换旧的。 Read this for more info。我认为您的 MVC 也升级了。 我刚刚阅读了你留下的所有帮助克林特伊斯特伍德的 cmets,干得好!世界需要更多像 You plusOne 这样的人 几乎成功了。但是我在迁移过程中遇到了错误EntityType 'IdentityUserRole' has no key defined,我通过将base.OnModelCreating(modelBuilder); 添加到OnModelCreating 函数来解决它。【参考方案2】:

这就是我将 Identity 与现有数据库集成的方法。

    使用 MVC 模板创建示例 MVC 项目。这包含了 Identity 实现所需的所有代码 - Startup.Auth.cs、IdentityConfig.cs、Account Controller 代码、Manage Controller、Models 和相关视图。

    为 Identity 和 OWIN 安装必要的 nuget 包。通过查看示例项目中的参考资料和@Sam 的答案,您会有所了解

    将所有这些代码复制到您现有的项目中。请注意不要忘记为 Identity 添加“DefaultConnection”连接字符串以映射到您的数据库。请检查 IdentityModel.cs 中的 ApplicationDBContext 类,您将在其中找到对“DefaultConnection”连接字符串的引用。

    这是我在现有数据库上运行以创建必要表的 SQL 脚本:

    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
    

    检查并解决任何剩余的错误,您就完成了。身份将处理其余的 :)

【讨论】:

非常感谢您的回复和很好的解释。其实我想用另一种方法,但我也会尝试一下。投票+ 我认为这是一种更清洁的方法 除了 Startup.Auth.cs 类之外,您还需要复制位于示例项目根目录的 Startup.cs。 Shyamal 你能从@Padmika 的评论中添加 Startup.cs 吗?这很重要。【参考方案3】:

我推荐IdentityServer。这是一个.NET Foundation 项目,涵盖了有关身份验证和授权的许多问题。

概述

IdentityServer 是一个基于 .NET/Katana 的框架和可托管组件,允许使用 OpenID Connect 和 OAuth2 等协议为现代 Web 应用程序和 API 实施单点登录和访问控制。它支持各种客户端,例如移动、Web、SPA 和桌面应用程序,并且可以扩展以允许集成到新的和现有的架构中。

如需了解更多信息,例如

支持 MembershipReboot 和基于 ASP.NET 身份的用户存储 支持额外的 Katana 身份验证中间件(例如 Google、 推特、脸书等) 支持基于 EntityFramework 的配置持久性 支持 WS-Federation 可扩展性

查看documentation 和demo。

【讨论】:

在盲目跳入 IdentityServer 实现之前,应考虑 IdentityServer 的实际用途。【参考方案4】:

好吧,我知道我可能为时已晚。 这适用于那些已经进行过一次或多次迁移的人。那些项目运行良好,那些在数据库中有 AspNet 表,但没有与这些相关的控制器、模型和视图。 我也遇到了同样的问题。我在开始时没有激活身份验证就开始了我的项目。然后我意识到我没有用于身份验证的所有元素(Views 文件夹中的 Account 和 Manage,控制器中的 accountController 和 ManageControler,以及模型中的 AccountViewModel 和 ManageViewModel)。 我刚刚创建了具有类似设置、名称的其他项目,并在创建该项目时激活了身份验证。 然后我设法将丢失的文件复制到我的初始项目中。 在那之后,我经历了每一个改变命名空间和导入到我项目的命名空间

【讨论】:

以上是关于将 ASP.NET MVC5 身份验证添加到现有项目的主要内容,如果未能解决你的问题,请参考以下文章

ASP.Net MVC 5 身份验证与另一个 MVC 5 身份网站

如何使用 ASP.NET Core Identity 将登录/注册系统添加到现有数据库?

ASP.NET MVC5 OWIN Facebook 身份验证突然不起作用

我们可以在不使用 ASP.Net Identity 的情况下使用 MVC 5 提供的 cookie 身份验证吗?

带有 Windows 身份验证的 ASP.NET Core 2.1 自定义 RoleProvider

ASP.NET Core MVC:使用 SQL Server 身份验证连接到现有数据库