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

ASP.NET Core身份认证与授权能否对接Active Directory?求实现示例

ASP.NET Core 身份认证与Active Directory整合方案

你完全可以让ASP.NET Core的身份认证与授权(I&A)系统对接Active Directory,无需让用户维护两个账号,以下是几种可行的实现方案和完整示例:

一、核心对接方案

1. 域环境下的Windows身份认证(零表单自动登录)

如果应用部署在域内网环境,可直接启用Windows身份认证,ASP.NET Core会自动对接AD完成身份验证:

  • 在Program.cs中配置:
builder.Services.AddAuthentication(IISDefaults.AuthenticationScheme);
builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
});

用户访问应用时会自动通过域账号登录,完全复用AD身份,无需额外登录操作。

2. 表单登录对接AD(支持非域/外网场景)

需要表单登录界面时,可通过System.DirectoryServices.AccountManagement库直接验证AD账号密码:

  • 先安装NuGet包:Install-Package System.DirectoryServices.AccountManagement
  • 核心验证逻辑(登录控制器中):
using System.DirectoryServices.AccountManagement;

public async Task<IActionResult> Login(LoginModel model)
{
    if (!ModelState.IsValid) return View(model);

    // 替换为你的域名称(如"contoso.com"或域控制器IP)
    using var context = new PrincipalContext(ContextType.Domain, "YOUR_DOMAIN");
    if (context.ValidateCredentials(model.Username, model.Password))
    {
        var adUser = UserPrincipal.FindByIdentity(context, model.Username);
        // 构建Claims身份并完成登录
        var claims = new List<Claim>
        {
            new(ClaimTypes.Name, adUser.DisplayName),
            new(ClaimTypes.NameIdentifier, adUser.SamAccountName),
            new(ClaimTypes.Email, adUser.Email ?? string.Empty)
        };
        // 可选:将AD组映射为角色
        foreach (var group in adUser.GetAuthorizationGroups().OfType<GroupPrincipal>())
        {
            claims.Add(new(ClaimTypes.Role, group.Name));
        }

        var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
        await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity),
            new AuthenticationProperties { IsPersistent = model.RememberMe });

        return RedirectToAction("Index", "Home");
    }

    ModelState.AddModelError("", "用户名或密码错误");
    return View(model);
}
  • 同时在Program.cs配置Cookie认证:
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.LoginPath = "/Account/Login";
        options.ExpireTimeSpan = TimeSpan.FromHours(8);
    });
builder.Services.AddAuthorization();

3. 结合ASP.NET Core Identity与AD(保留Identity功能)

如果需要保留Identity的用户管理、角色扩展等功能,可将密码验证委托给AD:

  • 自定义AD密码验证器:
public class AdPasswordValidator<TUser> : IPasswordValidator<TUser> where TUser : class
{
    public async Task<IdentityResult> ValidateAsync(UserManager<TUser> manager, TUser user, string password)
    {
        var username = await manager.GetUserNameAsync(user);
        using var context = new PrincipalContext(ContextType.Domain, "YOUR_DOMAIN");
        return context.ValidateCredentials(username, password) 
            ? IdentityResult.Success 
            : IdentityResult.Failed(new IdentityError { Description = "AD账号密码验证失败" });
    }
}
  • 在Program.cs替换默认验证器:
builder.Services.AddDefaultIdentity<IdentityUser>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddPasswordValidator<AdPasswordValidator<IdentityUser>>();

这种方式下,用户账号存储在Identity数据库,但密码验证完全依赖AD,兼顾两种系统的优势。

二、表单登录对接AD的完整示例

1. 登录Model

public class LoginModel
{
    [Required]
    [Display(Name = "用户名")]
    public string Username { get; set; }

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

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

2. 登录视图(Login.cshtml)

@model LoginModel

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

<h1>@ViewData["Title"]</h1>
<div class="row">
    <div class="col-md-4">
        <form asp-action="Login">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Username" class="control-label"></label>
                <input asp-for="Username" class="form-control" />
                <span asp-validation-for="Username" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Password" class="control-label"></label>
                <input asp-for="Password" class="form-control" />
                <span asp-validation-for="Password" class="text-danger"></span>
            </div>
            <div class="form-group">
                <div class="checkbox">
                    <label asp-for="RememberMe">
                        <input asp-for="RememberMe" /> @Html.DisplayNameFor(model => model.RememberMe)
                    </label>
                </div>
            </div>
            <div class="form-group">
                <input type="submit" value="登录" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

3. Program.cs完整配置

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();

// 配置Cookie认证
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {
        options.LoginPath = "/Account/Login";
        options.AccessDeniedPath = "/Account/AccessDenied";
        options.ExpireTimeSpan = TimeSpan.FromHours(8);
        options.SlidingExpiration = true;
    });

// 配置全局授权策略
builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
});

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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 15:45:21