c# - 尝试使用 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;
}
}
解决方案
首先,如果将变量声明为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
)都是通过一个网络请求而不是两个网络请求完成的。
推荐阅读
- c# - 为什么模拟存储库需要一个虚函数,而模拟 IRepository 会覆盖现有函数?
- node.js - await 总是抛出 SyntaxError:await 仅在 sequelize 的异步函数中有效
- javascript - 最后一个缩略图没有出现在视图中(react-responsive-carousel)
- c# - C# 模式匹配是否支持多种类型?
- c++ - 为什么 cin.clear() 没有重置故障位状态?
- node.js - 如何使用任何 npm 包从数据库中生成和下载具有动态图像路径的 pdf
- java - Eclipse Gradle 项目中的线程“main”java.lang.NoClassDefFoundError 中的异常
- java - 如果不使用 else 语句,我们如何使用三元运算符?
- sql - presto/athena 有没有办法根据条件获取列名并在 group by 中使用它?
- javascript - 将 SVG 作为图像复制到剪贴板