You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何将Novell.Directory.Ldap与ASP.NET Core身份认证结合实现AD组验证?

Combining Novell.Directory.Ldap with ASP.NET Authentication

Absolutely! I’ve helped several developers pull off exactly this setup—combining Novell.Directory.Ldap for Active Directory checks with ASP.NET authentication. Let me walk you through the most common, reliable approaches folks use.

1. Custom Authentication Handler (ASP.NET Core)

If you’re working with ASP.NET Core, building a custom AuthenticationHandler is the most flexible way to integrate your existing LDAP logic. This lets you plug your AD validation directly into the framework’s authentication pipeline:

Step-by-Step Implementation

  • Grab user credentials from the request (form data, headers, etc.)
  • Use your existing Novell.Directory.Ldap code to validate the user’s AD credentials and check group membership
  • If validation passes, generate a ClaimsPrincipal with user details and group-based claims
  • Attach the principal to the request to complete authentication

Example Code

public class LdapAuthHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
    public LdapAuthHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, 
                           ILoggerFactory logger, 
                           UrlEncoder encoder, 
                           ISystemClock clock) 
        : base(options, logger, encoder, clock) { }

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        // Pull credentials from form (adjust for your auth method: Bearer, etc.)
        var username = Request.Form["username"].FirstOrDefault();
        var password = Request.Form["password"].FirstOrDefault();

        if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
            return AuthenticateResult.Fail("Missing username or password");

        try
        {
            // Your existing LDAP validation logic
            using var ldapConn = new LdapConnection();
            ldapConn.Connect("your-ad-server.domain.com", 389);
            ldapConn.Bind($"CN={username},OU=Employees,DC=domain,DC=com", password);

            // Check if user is in your target group
            var isAuthorized = IsUserInTargetGroup(ldapConn, username, "YourRestrictedGroup");

            if (!isAuthorized)
                return AuthenticateResult.Fail("User not in required security group");

            // Build claims for the authenticated user
            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.Name, username),
                new Claim(ClaimTypes.Role, "RestrictedGroupMember")
            };
            var identity = new ClaimsIdentity(claims, Scheme.Name);
            var principal = new ClaimsPrincipal(identity);
            var authTicket = new AuthenticationTicket(principal, Scheme.Name);

            return AuthenticateResult.Success(authTicket);
        }
        catch (LdapException ex)
        {
            return AuthenticateResult.Fail($"LDAP error: {ex.Message}");
        }
    }

    // Your existing group-check logic (adapt to your AD structure)
    private bool IsUserInTargetGroup(LdapConnection conn, string username, string groupName)
    {
        var searchFilter = $"(&(objectClass=group)(name={groupName}))";
        var searchResults = conn.Search("DC=domain,DC=com", 
                                       LdapConnection.SCOPE_SUB, 
                                       searchFilter, 
                                       new[] { "member" }, 
                                       false);

        while (searchResults.HasMore())
        {
            var groupEntry = searchResults.Next();
            var members = groupEntry.GetAttribute("member")?.StringValueArray;
            if (members != null && members.Any(m => m.Contains($"CN={username}")))
                return true;
        }
        return false;
    }
}

Register the Handler in Program.cs

builder.Services.AddAuthentication("LdapScheme")
    .AddScheme<AuthenticationSchemeOptions, LdapAuthHandler>("LdapScheme", opts => { });

builder.Services.AddAuthorization(opts =>
{
    opts.AddPolicy("RequireRestrictedGroup", policy =>
        policy.RequireRole("RestrictedGroupMember"));
});

2. Extend ASP.NET Identity (If You’re Using the Identity Framework)

If you already have ASP.NET Identity set up, you can extend its validation pipeline to include your LDAP checks:

Option: Custom User Validator

Create a custom IUserValidator that runs your LDAP validation alongside Identity’s default checks:

public class LdapUserValidator<TUser> : IUserValidator<TUser> where TUser : class
{
    public async Task<IdentityResult> ValidateAsync(UserManager<TUser> manager, TUser user)
    {
        var username = await manager.GetUserNameAsync(user);
        // Note: Get the password from your login request context
        var password = ""; 

        // Run LDAP auth check
        var isLdapAuthenticated = await ValidateLdapCredentials(username, password);
        var isInRequiredGroup = await CheckUserGroupMembership(username);

        if (!isLdapAuthenticated)
            return IdentityResult.Failed(new IdentityError { Description = "Invalid AD credentials" });

        if (!isInRequiredGroup)
            return IdentityResult.Failed(new IdentityError { Description = "User not in authorized group" });

        return IdentityResult.Success;
    }

    private async Task<bool> ValidateLdapCredentials(string username, string password)
    {
        try
        {
            using var conn = new LdapConnection();
            conn.Connect("your-ad-server.domain.com", 389);
            conn.Bind($"CN={username},OU=Employees,DC=domain,DC=com", password);
            return true;
        }
        catch
        {
            return false;
        }
    }

    private async Task<bool> CheckUserGroupMembership(string username)
    {
        // Reuse your existing group-check logic here
        return true;
    }
}

Register the Validator

builder.Services.AddScoped<IUserValidator<ApplicationUser>, LdapUserValidator<ApplicationUser>>();

Key Considerations

  • Connection Pooling: Avoid creating a new LDAP connection for every request—implement a connection pool to boost performance.
  • Secure Connections: Use LDAPS (port 636) instead of plain LDAP to encrypt credentials in transit.
  • Least Privilege: Use a read-only AD service account for group queries instead of relying on the user’s credentials.
  • Error Handling: Catch specific LDAP exceptions (e.g., invalid credentials, connection failures) to return meaningful feedback to users.

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

火山引擎 最新活动