You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core 7 MVC Windows身份认证:替换浏览器登录弹窗为自定义登录表单的配置咨询

ASP.NET Core 7 MVC Windows身份认证:替换浏览器登录弹窗为自定义登录表单的配置咨询

没问题,我来帮你理清思路。首先得明确:纯Windows身份认证(依赖NTLM/Kerberos协议)是和浏览器深度绑定的,默认就是弹出系统级的登录弹窗。如果要换成自定义的表单登录,你需要结合Cookie认证,把Windows账号的验证逻辑搬到自己的表单里,或者同时保留两种认证选项(让用户选表单或自动Windows登录)。

下面是具体的实现步骤和代码示例,一步步来:

1. 调整项目的认证配置(Program.cs)

首先要修改Program.cs,把Cookie认证设为默认的挑战方案(这样未授权请求会跳转到你的自定义登录页,而不是弹出系统弹窗),同时保留Windows认证的能力(如果你需要的话)。

var builder = WebApplication.CreateBuilder(args);

// 添加MVC服务
builder.Services.AddControllersWithViews();

// 配置认证体系:Cookie认证为主,Windows认证为辅
builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme; // 未授权时跳转到Cookie的登录页
})
.AddCookie(options =>
{
    options.LoginPath = "/Account/Login"; // 指定自定义登录页的路径
    options.AccessDeniedPath = "/Account/AccessDenied";
    options.ExpireTimeSpan = TimeSpan.FromHours(2); // Cookie有效期,按需调整
})
.AddNegotiate(); // ASP.NET Core 7+推荐用AddNegotiate替代旧的AddWindows,支持NTLM/Kerberos

// 添加授权服务
builder.Services.AddAuthorization();

var app = builder.Build();

// 中间件顺序很重要:认证必须在授权之前
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

// 先启用认证,再启用授权
app.UseAuthentication();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

2. 创建登录相关的控制器和视图

接下来需要做一个登录表单,收集用户的域/本地账号密码,然后验证其合法性,验证通过后颁发Cookie。

第一步:创建LoginViewModel(用于表单绑定)

在Models文件夹下新建LoginViewModel.cs:

using System.ComponentModel.DataAnnotations;

namespace YourAppName.Models;

public class LoginViewModel
{
    [Required(ErrorMessage = "请输入用户名")]
    [Display(Name = "用户名(域账号格式:DOMAIN\\Username 或 Username)")]
    public string Username { get; set; } = string.Empty;

    [Required(ErrorMessage = "请输入密码")]
    [DataType(DataType.Password)]
    [Display(Name = "密码")]
    public string Password { get; set; } = string.Empty;

    [Display(Name = "记住我")]
    public bool RememberMe { get; set; }
}

第二步:创建Account控制器

在Controllers文件夹下新建AccountController.cs,负责处理登录、登出逻辑,以及Windows认证的可选入口:

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Mvc;
using System.DirectoryServices.AccountManagement;
using System.Security.Claims;
using YourAppName.Models;

namespace YourAppName.Controllers;

public class AccountController : Controller
{
    // 显示登录表单
    [HttpGet]
    public IActionResult Login(string? returnUrl = null)
    {
        ViewData["ReturnUrl"] = returnUrl;
        return View();
    }

    // 处理表单提交的登录请求
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Login(LoginViewModel model, string? returnUrl = null)
    {
        ViewData["ReturnUrl"] = returnUrl;
        if (ModelState.IsValid)
        {
            // 验证用户的Windows账号密码
            bool isAuthenticated = ValidateWindowsCredentials(model.Username, model.Password);
            if (isAuthenticated)
            {
                // 创建用户身份标识(Claims)
                var claims = new List<Claim>
                {
                    new Claim(ClaimTypes.Name, model.Username),
                    new Claim(ClaimTypes.NameIdentifier, model.Username)
                    // 可以根据需求添加更多Claims,比如角色、部门等
                };

                var claimsIdentity = new ClaimsIdentity(
                    claims, CookieAuthenticationDefaults.AuthenticationScheme);

                var authProperties = new AuthenticationProperties
                {
                    IsPersistent = model.RememberMe, // 是否持久化Cookie(记住我)
                    RedirectUri = returnUrl ?? Url.Action("Index", "Home")
                };

                // 颁发认证Cookie
                await HttpContext.SignInAsync(
                    CookieAuthenticationDefaults.AuthenticationScheme,
                    new ClaimsPrincipal(claimsIdentity),
                    authProperties);

                // 跳转到用户原本要访问的页面
                return LocalRedirect(returnUrl ?? Url.Action("Index", "Home"));
            }
            else
            {
                ModelState.AddModelError(string.Empty, "用户名或密码错误,请重试");
            }
        }

        // 验证失败,返回登录页
        return View(model);
    }

    // 登出功能
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Logout()
    {
        await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
        return RedirectToAction("Index", "Home");
    }

    // 可选:提供Windows自动登录的入口(让用户可以选择用系统账号自动登录)
    [HttpGet]
    public IActionResult LoginWithWindows(string? returnUrl = null)
    {
        var properties = new AuthenticationProperties { RedirectUri = returnUrl ?? Url.Action("Index", "Home") };
        // 触发Windows认证挑战
        return Challenge(properties, NegotiateDefaults.AuthenticationScheme);
    }

    // 核心:验证Windows账号密码的方法
    private bool ValidateWindowsCredentials(string username, string password)
    {
        try
        {
            // 如果是域账号,用ContextType.Domain;如果是本地机器账号,用ContextType.Machine
            using var context = new PrincipalContext(ContextType.Domain);
            // 验证账号密码,支持DOMAIN\\Username 或 Username格式
            return context.ValidateCredentials(username, password);
        }
        catch (Exception ex)
        {
            // 可以在这里记录日志,比如认证失败的异常信息
            Console.WriteLine($"验证失败:{ex.Message}");
            return false;
        }
    }
}

第三步:创建登录视图

在Views文件夹下新建Account文件夹,然后新建Login.cshtml:

@{
    ViewData["Title"] = "用户登录";
}

<div class="container mt-5">
    <div class="row justify-content-center">
        <div class="col-md-6">
            <div class="card">
                <div class="card-header">
                    <h3>@ViewData["Title"]</h3>
                </div>
                <div class="card-body">
                    <form asp-action="Login" method="post">
                        <input type="hidden" asp-for="@ViewData["ReturnUrl"]" />
                        <div asp-validation-summary="All" class="text-danger mb-3"></div>

                        <div class="mb-3">
                            <label asp-for="Username" class="form-label"></label>
                            <input asp-for="Username" class="form-control" placeholder="例如:DOMAIN\\张三 或 张三" />
                            <span asp-validation-for="Username" class="text-danger"></span>
                        </div>

                        <div class="mb-3">
                            <label asp-for="Password" class="form-label"></label>
                            <input asp-for="Password" class="form-control" />
                            <span asp-validation-for="Password" class="text-danger"></span>
                        </div>

                        <div class="mb-3 form-check">
                            <input asp-for="RememberMe" class="form-check-input" />
                            <label asp-for="RememberMe" class="form-check-label"></label>
                        </div>

                        <div class="d-grid gap-2">
                            <button type="submit" class="btn btn-primary">登录</button>
                            <a asp-action="LoginWithWindows" asp-route-returnUrl="@ViewData["ReturnUrl"]" class="btn btn-secondary">使用Windows账号自动登录</a>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

3. 安装必要的NuGet包

因为用到了System.DirectoryServices.AccountManagement来验证Windows账号,需要安装对应的NuGet包:
打开NuGet包管理器,搜索并安装System.DirectoryServices.AccountManagement。

4. 测试效果

现在启动项目,当访问需要授权的页面时,会自动跳转到你自定义的登录表单,而不是弹出系统登录框。用户输入正确的Windows账号密码后,就能正常访问,后续请求会用Cookie维持登录状态。如果用户选择"使用Windows账号自动登录",则会触发原本的Windows认证流程(自动登录,不需要输入密码,前提是用户已经登录到域/本地机器)。


备注:内容来源于stack exchange,提问作者Anthony Mullen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 09:22:41