想要使用服务帐户连接到运行我的应用程序的AD

时间:2016-10-17 12:44:41

标签: c# active-directory

在我的MVC-5应用程序中,我通过我的应用程序添加/编辑活动目录中的用户。每当我在AD中进行更改时,每次我需要传递ldapUserName(Admin)和ldapPassword(传递@ 123)来连接到Active目录。然后我只能在AD中执行操作。每次我想使用服务帐户(domain \ service_account)运行我的应用程序以便连接到AD时,代替传递凭据。如何实现?

2 个答案:

答案 0 :(得分:0)

您可以选择以下两个选项之一。

选项1.您在加入域的计算机上运行应用程序,从中添加\删除用户。在这种情况下,最简单的解决方案是在具有足够权限的域帐户下运行您的应用程序(应用程序池)(以简单的方式可以是属于Domain Admins组的帐户。也将是主机上的管理员,应用程序运行的位置)

选项2.您在未加入域的独立计算机上运行应用程序。在这种情况下,您可以选择以下之一:

一个。在执行所有网络连接时,模拟您的线程充当域帐户。您需要使用带有LOGON32_LOGON_NEW_CREDENTIALS标志的LogonUser函数。该方法的缺点是所有网络连接(例如,您连接到网络共享)将在域帐户下进行。有关实施的更多详细信息,请参阅this post。

B中。创建一个连接管理器,它将为您创建具有所需凭据的DirectoryEntry。请参阅以下代码:

public interface IDirectoryEntryManager
{
    DirectoryEntry GetDirectoryEntry(string domain, string baseDn);
}

public interface ICredentialProvider
{
    Credential GetCredential(string domain);
}

public class Credential
{
    public string UserName { get; set; }
    public string Password { get; set; }
}

public class DirectoryEntryManager : IDirectoryEntryManager, IDisposable
{
    private class DomainConnectionInfo
    {
        internal DomainConnectionInfo(string server, Credential credential)
        {
            Server = server;
            Credential = credential;
        }

        internal string Server { get; private set; }
        internal Credential Credential { get; private set; }
    }

    private bool disposed;
    ICredentialProvider _credentialProvider;
    Dictionary<string, DomainConnectionInfo> connectionsInfo = new Dictionary<string, DomainConnectionInfo>(StringComparer.OrdinalIgnoreCase);
    Dictionary<string, DirectoryEntry> connections = new Dictionary<string, DirectoryEntry>(StringComparer.OrdinalIgnoreCase);

    public DirectoryEntryManager(ICredentialProvider credentialProvider)
    {
        _credentialProvider = credentialProvider;
    }

    public DirectoryEntry GetDirectoryEntry(string domain, string baseDn)
    {
        if (disposed)
        {
            throw new ObjectDisposedException(this.GetType().Name);
        }

        return GetOrCreateConnection(domain, baseDn);
    }

    public void Dispose()
    {
        if (!disposed)
        {
            foreach (var connection in connections)
            {
                connection.Value.Dispose();
            }

            connections.Clear();
            disposed = true;
        }
    }

    private DirectoryEntry GetOrCreateConnection(string domain, string baseDn)
    {
        DomainConnectionInfo info;

        if (!connectionsInfo.TryGetValue(domain, out info))
        {
            var credential = _credentialProvider.GetCredential(domain);
            var dc = DomainController.FindOne(new DirectoryContext(DirectoryContextType.Domain, credential.UserName, credential.Password));
            info = new DomainConnectionInfo(dc.Name, credential);

            // maintaining a connection to rootDse object to make all LDAP queries use this single connection under the hood. Increasing performance
            var entry = new DirectoryEntry(string.Format("LDAP://{0}/RootDSE", dc.Name));
            entry.RefreshCache();

            connections.Add(domain, entry);
            connectionsInfo.Add(domain, info);
        }

        return new DirectoryEntry(string.Format("LDAP://{0}/{1}", info.Server, baseDn), info.Credential.UserName, info.Credential.Password);
    }
}

没有测试代码。如果您在程序的一个部分中创建用户并尝试在另一个部分中访问它,则使用服务器绑定而不是无服务器绑定(例如LDAP://domain.com)会更好。使用无服务器绑定可以连接到不同的DC,因此您尝试访问的用户可能无法复制到第二个DC。

请注意,域控制器可能不可用,因此您需要实现逻辑,搜索另一个DC并在需要时刷新连接缓存。

您可以将凭证存储在可能已加密的文件\ LSA中,并将DirectoryEntryManager类设为单例。

答案 1 :(得分:0)

只需按DirectoryEntry创建new DirectoryEntry(ldabPath, null, null)即可使用当前用户的凭据(如果是Windows服务,则使用服务帐户)。关键是将 null 传递给用户名和密码。

这就是你想要的吗?

只需确保服务帐户有足够的权限为所有相关用户设置密码。