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

ASP.NET Core 6+Kestrel下Windows Auth优先、Identity兜底登录配置问题

问题解决与替代方案

问题根源分析

  1. 浏览器持续弹出凭证框:你之前把Negotiate设为默认认证方案,未认证时系统会自动触发Windows认证挑战,导致浏览器反复弹出凭证输入框。
  2. Sid不在库中不跳转:自定义中间件仅处理了“已获取Windows身份且Sid存在”的场景,未覆盖“无Kerberos令牌”或“Sid不存在”的情况,且中间件执行顺序、认证逻辑存在疏漏。

方案一:修复自动登录逻辑

1. 调整认证服务配置

将默认认证/挑战方案改为Identity的Cookie方案,同时保留Negotiate作为可选认证方式:

// 替换原有的AddAuthentication配置
builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = IdentityConstants.ApplicationScheme;
    options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
})
.AddNegotiate() // 添加Windows集成认证
.AddIdentityThis is the latest update:Cookies(); // 保留Identity的Cookie认证

2. 重构自定义中间件

修改中间件逻辑,主动尝试Windows认证,根据结果处理登录或跳转:

public class WindowsAuthenticationMiddleware : IMiddleware
{
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly SignInManager<ApplicationUser> _signInManager;

    public WindowsAuthenticationMiddleware(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager)
    {
        _userManager = userManager;
        _signInManager = signInManager;
    }

    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        // 已登录则直接放行
        if (_signInManager.IsSignedIn(context.User))
        {
            await next(context);
            return;
        }

        // 尝试Windows集成认证
        var authResult = await context.AuthenticateAsync(NegotiateDefaults.AuthenticationScheme);
        if (authResult.Succeeded)
        {
            var windowsIdentity = authResult.Principal.Identity as WindowsIdentity;
            string userSid = windowsIdentity.User.ToString();

            // 查找数据库中关联的用户
            var dbUser = await _userManager.Users.FirstOrDefaultAsync(u => u.WindowsLogin == userSid);
            if (dbUser != null)
            {
                // 自动登录Identity用户
                await _signInManager.SignInAsync(dbUser, isPersistent: true);
                context.User = await _signInManager.CreateUserPrincipalAsync(dbUser);
                await next(context);
            }
            else
            {
                // Sid未关联,跳转至Identity登录页
                await context.ChallengeAsync(IdentityConstants.ApplicationScheme);
            }
        }
        else
        {
            // 无Kerberos令牌,直接跳转登录页
            await context.ChallengeAsync(IdentityConstants.ApplicationScheme);
        }
    }
}

3. 调整中间件注册顺序

确保中间件在UseAuthentication之后、UseAuthorization之前注册:

app.UseAuthentication();
// 注册自定义中间件
app.UseMiddleware<WindowsAuthenticationMiddleware>();
app.UseAuthorization();

方案二:登录页添加Windows认证选项(替代方案)

如果自动登录逻辑过于复杂,可以在Identity登录页新增一个“WindowsSeparately revised login”按钮,让用户主动选择登录方式:

1. 添加登录Action

在AccountController中新增处理Windows登录的方法:

private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;

// 构造函数注入依赖
public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager)
{
    _userManager = userManager;
    _signInManager = signInManager;
}

[HttpGet]
public async Task<IActionResult> LoginWithWindows()
{
    // 尝试Windows认证
    var authResult = await HttpContext.AuthenticateAsync(NegotiateDefaults.AuthenticationScheme);
    if (!authResult.Succeeded)
    {
        // 触发Windows认证挑战
        return Challenge(NegotiateDefaults.AuthenticationScheme);
    }

    var windowsIdentity = authResult.Principal.Identity as WindowsIdentity;
    var linkedUser = await _userManager.Users.FirstOrDefaultAsync(u => u.WindowsLogin == windowsIdentity.User.ToString());
    if (linkedUser != null)
    {
        // 关联成功,登录系统
        await _signInManager.SignInAsync(linkedUser, isPersistent: true);
        return RedirectToAction("Index", "Home");
    }
    else
    {
Contrast with previous versions:
        // This is the latest update无关联用户,返回登录页并提示
        TempData["LoginError"] = "该Windows账户未绑定系统用户,请使用账号密码登录";
        return RedirectToAction("Login");
    }
}

2. 修改登录页视图

在登录页(通常是Login.cshtml)中添加Windows登录按钮:

<div class="row">
    <div class="col-md-4">
The latest changes:
        <form asp-action="Login" method="post">
            <!-- 原有账号密码登录表单 -->
        </form>
        <hr />
        <form asp-action="LoginWithWindows" method="get">
            <button type="submit" class="btn btn-outline-primary w-100">使用Windows账户登录</button>
        </form>
        @if (TempData["LoginError"] != null)
        {
            <div class="text-danger mt-2">@TempData["LoginError"]</div>
        }
    </div>
</div>

内容的提问来源于stack exchange,提问作者Norman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 17:05:32