首页 > 解决方案 > 尝试使用 ASP.net C# 更改 AD 用户时,调用错误的目标已引发异常

问题描述

我尝试了很多其他解决方案,但我仍然没有成功。有人能帮助我吗。我的代码是这样的:我看到了一些关于secureString的东西,我尝试使用它,但它仍然没有用。我也看到了另一种解决方案,它说在变量中使用 var 而不是 string。没用我不知道我做错了什么,或者那些解决方案不起作用。

public bool RedefinirSenha(string pUsuario, string pSenhaAtual, string pNovaSenha)
        {
            var NovaSenha = pNovaSenha;
            var SenhaAtual = pSenhaAtual;
            var Usuario = pUsuario;
            //string Pwd = String.Format(@"""{0}""", NovaSenha);
            //byte[] pwdCerto = System.Text.Encoding.Unicode.GetBytes(Pwd);

            try
            {
                string LDAP = myLDAPpath;
                DirectoryEntry ADcon = new DirectoryEntry(LDAP, Usuario, SenhaAtual, AuthenticationTypes.Secure);
                if (ADcon != null)
                {
                    DirectorySearcher search = new DirectorySearcher(ADcon);
                    search.Filter = "(SAMAccountName=" + Usuario + ")";
                    SearchResult result = search.FindOne();
                    if (result != null)
                    {
                        DirectoryEntry userEntry = result.GetDirectoryEntry();
                        if (userEntry != null)
                        {
                            try

                            {

                                userEntry.Invoke("ChangePassword", new object[] { SenhaAtual, NovaSenha }, AuthenticationTypes.Secure);
                                userEntry.Properties["LockOutTime"].Value = 0;
                                userEntry.CommitChanges();
                                userEntry.Close();
                                return true;
                            }
                            catch (Exception INex)
                            {

                                this.Erro = INex.Message + "COD:\r\n" + INex.InnerException;
                                userEntry.Close();
                                return false;
                            }

                        }
                    }
                }
                            return true;
            }
            catch (Exception ex)
            {
                this.Erro = ex.Message;
                return false;
            }
        }

标签: c#asp.netactive-directory

解决方案


首先,如果将变量声明为var或,在运行时将没有区别string。使用var关键字让编译器决定类型是什么。因为您正在为其分配 a string,所以它也是一个字符串。在大多数情况下,var没问题。只有在极少数情况下需要显式指定类型。

其次,DirectoryEntry.Invoke是这样定义的:

public object Invoke (string methodName, params object[] args);

看起来您需要传递一个object数组,但事实并非如此。params关键字是一种允许您将在方法内部使用的多个参数作为数组传递的方法。所以当你这样称呼它时:

userEntry.Invoke("ChangePassword", new object[] { SenhaAtual, NovaSenha }, AuthenticationTypes.Secure);

第一个参数是一个object数组,第二个参数是AuthenticationTypes.Secure,然后将这两个参数放入args数组中以在Invoke方法中使用。但这不是要ChangePassword寻找的。如果这对您没有意义,请阅读关键字的文档,params它应该会有所帮助。

当您调用 时.Invoke("ChangePassword", ...),它会调用本机 WindowsIADsUser.ChangePassword方法。这需要两个参数:astring带有旧密码和 astring带有新密码 - 不是object数组和AuthenticationTypes值。所以你应该这样称呼它:

userEntry.Invoke("ChangePassword", SenhaAtual, NovaSenha);

您无需担心身份验证,因为只能通过安全连接更改密码。在文档中,它说它的行为方式与 ( IADsUser.SetPassword]( https://docs.microsoft.com/en-ca/windows/win32/api/iads/nf-iads-iadsuser-setpassword ) 相同,它尝试了几次为您实现安全连接的不同方法。


DirectoryEntry如果连接已经通过安全连接,还有另一种方法可以更改密码。安全连接可以使用 Kerberos,这可以使用AuthenticationTypes.Sealing(如果您与域控制器在同一网络上,这是最好的):

var ADcon = new DirectoryEntry(LDAP, Usuario, SenhaAtual, AuthenticationTypes.Secure | AuthenticationTypes.Sealing);

或者,如果使用 LDAPS(基于 SSL 的 LDAP),您只需在 LDAP 路径中指定端口 636 即可使用(如果您与域控制器不在同一网络上,这是唯一的方法):

var ADcon = new DirectoryEntry("LDAP://example.com:636", Usuario, SenhaAtual);

如果你这样做了,那么你可以通过unicodePwd直接更新属性来更改密码,以它想要的非常具体的方式(用引号括起来并以 UTF-16 编码),如下所示:

userEntry.Properties["unicodePwd"].Remove(Encoding.Unicode.GetBytes($"\"{SenhaAtual}\""));
userEntry.Properties["unicodePwd"].Add(Encoding.Unicode.GetBytes($"\"{NovaSenha}\""));

这应该会稍微快一些,因为所有工作(更改密码和设置lockOutTime)都是通过一个网络请求而不是两个网络请求完成的。


推荐阅读