核心概念与准备工作

在开始编码之前,我们需要了解几个核心概念:

  1. 身份验证“你是谁?” 的过程,ASP.NET 提供了内置的身份验证机制,最常用的是 ASP.NET Identity,它是一个会员系统,负责处理用户注册、登录、密码哈希、角色管理等。
  2. 授权“你能做什么?” 的过程,在用户登录成功后,你可以授权他们访问特定的页面或执行特定的操作,只有管理员才能访问 /Admin 页面。
  3. Cookie:登录成功后,服务器会生成一个包含用户身份信息的“令牌”(通常是加密的字符串),并将其存储在用户的浏览器中,之后,用户每次请求网站时,浏览器都会自动带上这个 Cookie,服务器通过验证 Cookie 来识别用户。
  4. ASP.NET Core Identity vs. ASP.NET (Framework) Identity
    • ASP.NET Core Identity:是当前的主流和推荐方案,它更现代化、更灵活、支持 EF Core,并且可以轻松地与外部登录提供商(如 Google, Facebook, 微信)集成,适用于 ASP.NET Core 项目。
    • ASP.NET (Framework) Identity:是传统 ASP.NET MVC / Web Forms 中的身份验证系统,虽然功能强大,但已不再是新项目的首选,适用于 ASP.NET Framework 项目。

本指南将以 ASP.NET CoreASP.NET Core Identity 为例进行讲解,因为它代表了未来的方向。


实现步骤(以 ASP.NET Core MVC 为例)

我们将创建一个简单的登录流程。

步骤 1:创建项目并安装 NuGet 包

  1. 使用 Visual Studio 或 dotnet new 命令创建一个新的 ASP.NET Core Web 应用程序 (MVC 模板)。
  2. 项目模板通常会默认包含 Microsoft.AspNetCore.Identity.EntityFrameworkCore 包,如果没有,请通过 NuGet 包管理器安装它。

步骤 2:配置数据库和 Identity 服务

  1. 创建 DbContext: 在 Models 文件夹下,创建一个继承自 IdentityDbContext 的类。IdentityDbContext 已经包含了用户、角色、登录等所需的所有实体。

    // Models/ApplicationDbContext.cs
    using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
    using Microsoft.EntityFrameworkCore;
    namespace YourProjectName.Models
    {
        public class ApplicationDbContext : IdentityDbContext<IdentityUser>
        {
            public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
                : base(options)
            {
            }
            // 在这里可以添加你自己的实体,Products, Orders 等
        }
    }
  2. 注册服务: 在 Program.cs 文件中,将 ApplicationDbContext 和 Identity 服务注册到依赖注入容器中。

    // Program.cs
    using Microsoft.AspNetCore.Identity;
    using Microsoft.EntityFrameworkCore;
    using YourProjectName.Models;
    var builder = WebApplication.CreateBuilder(args);
    // 1. 添加数据库服务
    builder.Services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
    // 2. 添加 Identity 服务
    builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();
    // 添加其他服务,如 Controllers, Views 等
    builder.Services.AddControllersWithViews();
    var app = builder.Build();
    // ... (中间件配置)
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseRouting();
    // 3. 添加身份验证中间件
    app.UseAuthentication(); // 必须在 UseAuthorization 之前
    app.UseAuthorization();
    app.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
    app.Run();
    • 注意UseAuthentication() 中间件是必须的,它会负责处理 Cookie 的读取和验证。
    • AddDefaultIdentity 是一个快捷方法,它会帮你配置好大部分默认设置。SignIn.RequireConfirmedAccount = true 表示需要用户验证邮箱后才能登录,你可以先设为 false
  3. 配置数据库连接字符串: 在 appsettings.json 文件中,添加一个 SQL Server 连接字符串,你需要先在本地 SQL Server 中创建一个数据库。

    {
      "ConnectionStrings": {
        "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-YourProjectName-xxxxxxxxxxxx;Trusted_Connection=True;MultipleActiveResultSets=true"
      },
      // ... 其他配置
    }

    (使用 LocalDB 是最简单的方式,它会自动在文件系统中创建一个数据库文件)

步骤 3:应用数据库迁移

Identity 使用 Entity Framework 的 Code First 功能,你需要创建并应用一个迁移来生成存储用户信息的数据库表。

  1. 打开 程序包管理器控制台 (Package Manager Console)。

  2. 运行以下命令:

    Add-Migration InitialCreate
    Update-Database
    • Add-Migration 会根据你的 DbContext 创建一个迁移脚本。
    • Update-Database 会执行这个脚本,在数据库中创建 AspNetUsers, AspNetRoles 等表。

步骤 4:创建登录相关的 UI

  1. 注册: 默认的 MVC 模板已经为你生成了 AccountControllerRegisterLoginLogout 等相关的 Action 和 View。

    • 注册页面/Identity/Account/Register
    • 登录页面/Identity/Account/Login
    • 登出页面/Identity/Account/Logout

    你可以直接访问这些 URL 来测试注册和登录功能,它们已经包含了基本的表单和样式。

  2. 自定义登录页面(可选): 如果你想使用自己的登录页面而不是默认的,可以这样做:

    • Views/Account 文件夹下创建一个 Login.cshtml 文件。
    • AccountController 中,创建一个返回 View()Login Action。
    • _Layout.cshtml 中,添加一个指向你登录页面的链接。

步骤 5:在代码中检查用户登录状态

我们可以在控制器或视图中保护某些页面,只允许已登录的用户访问。

  1. 使用 [Authorize] 特性: 这是最简单的方式,在控制器或 Action 上添加此特性。

    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    namespace YourProjectName.Controllers
    {
        [Authorize] // 整个控制器都需要登录才能访问
        public class DashboardController : Controller
        {
            public IActionResult Index()
            {
                // 只有登录用户才能看到这个页面
                return View();
            }
            [AllowAnonymous] // 允许匿名用户访问这个特定的 Action
            public IActionResult PublicInfo()
            {
                return View();
            }
        }
    }
  2. 在代码中检查: 你也可以在 Action 内部手动检查。

    public class ProfileController : Controller
    {
        public IActionResult Index()
        {
            if (User.Identity.IsAuthenticated)
            {
                // 用户已登录,可以获取用户信息
                var userName = User.Identity.Name;
                // ... 其他逻辑
                return View();
            }
            else
            {
                // 用户未登录,可以重定向到登录页面
                return RedirectToAction("Login", "Account");
            }
        }
    }
  3. 获取当前用户信息: 通过依赖注入获取 UserManagerSignInManager 来操作用户。

    public class ProfileController : Controller
    {
        private readonly UserManager<IdentityUser> _userManager;
        // 通过构造函数注入 UserManager
        public ProfileController(UserManager<IdentityUser> userManager)
        {
            _userManager = userManager;
        }
        public async Task<IActionResult> Index()
        {
            var user = await _userManager.GetUserAsync(User);
            if (user == null)
            {
                return NotFound();
            }
            // 可以获取更多用户信息,如 Email, PhoneNumber 等
            var email = await _userManager.GetEmailAsync(user);
            // ... 将数据传递给 View
            return View();
        }
    }

安全最佳实践

实现登录功能,安全是重中之重。

  1. 绝不存储明文密码: ASP.NET Identity 会自动使用 BCryptPBKDF2 等强哈希算法对密码进行加盐哈希存储,你永远不要自己实现密码加密逻辑,直接使用 Identity 提供的 CreateAsync 方法即可。

  2. 使用 HTTPS: 在 Program.cs 中,强制使用 HTTPS,这可以防止登录凭据在网络传输中被窃听。

    app.UseHttpsRedirection();
  3. 防止暴力破解: 默认情况下,Identity 内置了登录失败次数限制和锁定机制,你可以在 Program.cs 中配置它。

    builder.Services.AddIdentity<IdentityUser, IdentityRole>(options =>
    {
        // 密码设置
        options.Password.RequireDigit = true;
        options.Password.RequireLowercase = true;
        options.Password.RequireNonAlphanumeric = true;
        options.Password.RequireUppercase = true;
        options.Password.RequiredLength = 8;
        options.Password.RequiredUniqueChars = 1;
        // 登录锁定设置
        options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
        options.Lockout.MaxFailedAccessAttempts = 5;
        options.Lockout.AllowedForNewUsers = true;
    })
    .AddEntityFrameworkStores<ApplicationDbContext>();
  4. 防止跨站请求伪造: 默认情况下,ASP.NET Core MVC 会为表单自动生成并验证防伪令牌,你不需要做太多事情,只需确保在表单中使用 @Html.AntiForgeryToken()

    <form asp-action="Login" asp-controller="Account">
        @Html.AntiForgeryToken() <!-- 重要! -->
        <div>
            <label>用户名:</label>
            <input type="text" name="Input.Username" />
        </div>
        <div>
            <label>密码:</label>
            <input type="password" name="Input.Password" />
        </div>
        <button type="submit">登录</button>
    </form>
  5. 设置安全的 Cookie: 在 Program.cs 中配置 Cookie 的安全属性。

    builder.Services.ConfigureApplicationCookie(options =>
    {
        options.Cookie.HttpOnly = true; // 防止 XSS 攻击
        options.ExpireTimeSpan = TimeSpan.FromMinutes(30); // Cookie 过期时间
        options.SlidingExpiration = true; // 滑动过期,每次访问都会重置计时器
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always; // 只在 HTTPS 下发送
    });

总结与新技术

特性 ASP.NET Core Identity (推荐) ASP.NET Framework Identity (旧版)
技术栈 EF Core, .NET Core EF6, .NET Framework
数据库 EF Core 支持 (SQL Server, SQLite, PostgreSQL, MySQL 等) EF6 支持
灵活性 极高,支持无 SQL、外部登录、自定义存储 较高,但扩展不如 Core 方便
OAuth/OpenID 原生支持,易于集成 需要额外配置或使用第三方库
社区与未来 活跃,是未来的方向 维护中,不再推荐新项目使用

对于新项目,请毫不犹豫地选择 ASP.NET Core 和 ASP.NET Core Identity。

通过以上步骤,你已经掌握了在 ASP.NET 网站中实现一个安全、可靠的用户登录系统的核心方法,从配置、数据库迁移、UI 创建到安全实践,每一步都至关重要,希望这个详细的指南能帮助你顺利完成开发!