C#查询Active Directory

C# Query Active Directory
2021-03-07
  •  译文(汉语)
  •  原文(英语)

我正在开发Intranet Web应用程序,并且正在使用System.DirectoryServices.AccountManagement来查询当前用户的Windows身份的Active Directory.在我的开发机器上,查询返回一个UserPrincipal,其中填充了用户信息.我的计算机上本地IIS的"默认网站"下的应用程序目录已启用Windows身份验证和"模拟".但是,当应用程序发布到我们的托管IIS时,将返回Principal,但没有用户信息.有人知道为什么吗?服务器管理员说,我必须使用服务帐户和密码连接到AD服务器才能执行查询.如果是真的,那么从我的本地计算机查询也不应该起作用.它是否正确?

public class LDAP_Helper
{
    public string NetworkName { get; private set; }
    public string LastName { get; private set; }
    public string FirstName { get; private set; }
    public string MiddleName { get; private set; }
    public string Email { get; private set; }
    public string VoicePhone { get; private set; }

    public LDAP_Helper()
    {
        using (var context = new System.DirectoryServices.AccountManagement.PrincipalContext(
            System.DirectoryServices.AccountManagement.ContextType.Domain))
        {
            try
            {
                string currentUser = HttpContext.Current.User.Identity.Name;
                var principal = System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity(context, currentUser);

                NetworkName = principal.SamAccountName;
                LastName = principal.Surname;
                FirstName = principal.GivenName;
                MiddleName = principal.MiddleName;
                Email = principal.EmailAddress;
                VoicePhone = principal.VoiceTelephoneNumber;
            }
            catch { }

        }

        return;
    }

Web.config settig:

    <identity impersonate="true" />

C#查询Active Directory C#查询Active Directory

解决过程1

首先,您会捕获所有异常,而对它们不执行任何操作,所以不好.如果确实处理了该异常,则可能首先会收到一个PrincipalOperationException,告诉您找不到该名称的用户,然后是6个NullReferenceExceptions,因为您的主体变量为Nothing.我不是C#专家,但是这个VB位应该不太难翻译.创建上下文时,还应该指定域,以避免在具有多个域控制器的网络上出现问题.您确实需要具有查询Active Directory服务器的权限,但是决不是必须是服务帐户.只是具有适当组成员身份的普通帐户.

 Public Function FindUserPrincipal(ByVal userName As String) As UserPrincipal
    Try
        Return UserPrincipal.FindByIdentity(New PrincipalContext(ContextType.Domain, "mydomain"), IdentityType.SamAccountName, userName)
    Catch ex As PrincipalOperationException
        Return Nothing
    End Try
End Function

通过在创建上下文时以LDAP可分辨名称的形式指定搜索根,还可以将搜索范围缩小到服务器上的单个组织单位,这可以显着提高大型网络的性能.

Private Function GetPrincipalContext(ByVal domain As String, ByVal ldapDn As String) As PrincipalContext
    Try
        If String.IsNullOrWhiteSpace(ldapDn) Then
            Return New PrincipalContext(ContextType.Domain, domain)
        Else
            Return New PrincipalContext(ContextType.Domain, domain, ldapDn)
        End If
    Catch ex As PrincipalOperationException
        Return Nothing
    End Try
End Function
速聊1:
感谢您的答复.我的组织不允许匿名查询.如何将有权查询广告的帐户放在哪里?我相信我的应用无法正常运行的原因是因为托管IIS使用了其I_UserMachine帐户,甚至我的web.config也明确启用了模拟.
速聊2:
抱歉,我没有意识到这是针对Web应用程序的.您可能会冒充,但那是非常不安全的,您将向外界开放广告.我在上面写了第二个答复,以某种方式混淆了我的帐户.使用证书身份验证创建安全的Web服务,以提升的特权托管该服务,并将证书提供给您的Web应用程序.您的Web应用通过安全通道查询Web服务,然后该服务查询AD.
解决过程2

您可以在PrincipalContext构造函数中指定一个用户名和密码来连接商店.这是MSDN文档链接.

解决过程3

解决此问题的最简单方法是设置WCF服务以处理与Active Directory的交互,并让您的Web应用程序以特权帐户运行该服务.这样,只有服务需要提升运行,客户端才需要能够访问该服务.

I am developing an Intranet web app and I am using the System.DirectoryServices.AccountManagement to query the Active Directory of the current user's Windows Identity. On my development machine, the query returns a UserPrincipal populated with the user information. The application directory under Default Web Site of the local IIS on my machine has Windows authentication and Impersonate enabled. However, when the application is published to our hosting IIS, the Principal is returned but with no user information. Does anyone know why? The server admin said that I have to use a service account and password to connect to AD server to do the query. If it's true, then querying from my local machine should have not worked either. Is this correct?

public class LDAP_Helper
{
    public string NetworkName { get; private set; }
    public string LastName { get; private set; }
    public string FirstName { get; private set; }
    public string MiddleName { get; private set; }
    public string Email { get; private set; }
    public string VoicePhone { get; private set; }

    public LDAP_Helper()
    {
        using (var context = new System.DirectoryServices.AccountManagement.PrincipalContext(
            System.DirectoryServices.AccountManagement.ContextType.Domain))
        {
            try
            {
                string currentUser = HttpContext.Current.User.Identity.Name;
                var principal = System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity(context, currentUser);

                NetworkName = principal.SamAccountName;
                LastName = principal.Surname;
                FirstName = principal.GivenName;
                MiddleName = principal.MiddleName;
                Email = principal.EmailAddress;
                VoicePhone = principal.VoiceTelephoneNumber;
            }
            catch { }

        }

        return;
    }

Web.config settig:

    <identity impersonate="true" />

C# Query Active Directory C# Query Active Directory

Solutions1

First off, you catch all exceptions and do nothing about them, so that's not good. If you did handle the exception, you would probably get first a PrincipalOperationException telling you that no user by that name was found, and then 6 NullReferenceExceptions because your principal variable is Nothing. I am not a C# guy, but this VB bit should not be too hard to translate. You should also specify the domain when you create the context to avoid problems on networks with multiple domain controllers. You do need to have permissions to query the Active Directory server, but by no means does that have to be a service account. Just a regular account with the appropriate group membership.

 Public Function FindUserPrincipal(ByVal userName As String) As UserPrincipal
    Try
        Return UserPrincipal.FindByIdentity(New PrincipalContext(ContextType.Domain, "mydomain"), IdentityType.SamAccountName, userName)
    Catch ex As PrincipalOperationException
        Return Nothing
    End Try
End Function

You can also narrow your search to a single organizational unit on the server by specifying the search root in the form of a LDAP distinguished name when you create the context, that can significantly improve performance on large networks.

Private Function GetPrincipalContext(ByVal domain As String, ByVal ldapDn As String) As PrincipalContext
    Try
        If String.IsNullOrWhiteSpace(ldapDn) Then
            Return New PrincipalContext(ContextType.Domain, domain)
        Else
            Return New PrincipalContext(ContextType.Domain, domain, ldapDn)
        End If
    Catch ex As PrincipalOperationException
        Return Nothing
    End Try
End Function
Talk1:
Thank you for the reply. My organization does not allow anonymous query. Where do I put the account that has permission to query the AD? I believe the reason my app is not working is because the hosting IIS uses its I_UserMachine account even my web.config explicitly enable Impersonation.
Talk2:
I am sorry I wasn't realizing this was for a web app. You could impersonate but that would be very insecure, you would be opening up AD to the outside world. I wrote the second reply above, somehow my accounts got mixed up. Create a secure web service with certificate authentication, host that service with elevated privileges, and give the certificate to your web app. Your web app queries your web service through a secure channel, and the service queries AD.
Solutions2

You can specify a username and password in the PrincipalContext constructor to connect to the store with. Here's the MSDN documentation link.

Solutions3

The easiest way to deal with this would be to setup a WCF service to handle interaction with Active Directory, and have your web app query that service, running under a privileged account. This way only the service needs to run elevated, the client just needs to be able to reach the service.

转载于:https://stackoverflow.com/questions/23003279/c-sharp-query-active-directory

本人是.net程序员,因为英语不行,使用工具翻译,希望对有需要的人有所帮助
如果本文质量不好,还请谅解,毕竟这些操作还是比较费时的,英语较好的可以看原文

留言回复
我们只提供高质量资源,素材,源码,坚持 下了就能用 原则,让客户花了钱觉得值
上班时间 : 周一至周五9:00-17:30 期待您的加入