【发布时间】:2015-04-21 07:03:01
【问题描述】:
我们有一个 mvc 应用程序,它使用 Active Directory 来验证我们的用户。我们正在利用System.DirectoryServices 并使用PricipalContext 进行身份验证:
_principalContext.ValidateCredentials(userName, pass, ContextOptions.SimpleBind);
然而,这个方法只返回一个布尔值,我们希望返回更好的消息,甚至将用户重定向到密码重置屏幕,例如:
- 用户的帐户被锁定。
- 用户密码已过期。
- 用户需要在下次登录时更改密码。
因此,如果用户无法登录,我们调用NetValidatePasswordPolicy 来查看用户无法登录的原因。这似乎运作良好,但我们意识到无论状态如何,此方法都只会返回NET_API_STATUS.NERR_PasswordMustChange Active Directory 用户是。
我发现的唯一一个同样问题的例子来自一个 Sublime Speech 插件here。我使用的代码如下:
var outputPointer = IntPtr.Zero;
var inputArgs = new NET_VALIDATE_PASSWORD_CHANGE_INPUT_ARG { PasswordMatched = false, UserAccountName = username };
inputArgs.ClearPassword = Marshal.StringToBSTR(password);
var inputPointer = IntPtr.Zero;
inputPointer = Marshal.AllocHGlobal(Marshal.SizeOf(inputArgs));
Marshal.StructureToPtr(inputArgs, inputPointer, false);
using (new ComImpersonator(adImpersonatingUserName, adImpersonatingDomainName, adImpersonatingPassword))
{
var status = NetValidatePasswordPolicy(serverName, IntPtr.Zero, NET_VALIDATE_PASSWORD_TYPE.NetValidateAuthentication, inputPointer, ref outputPointer);
if (status == NET_API_STATUS.NERR_Success)
{
var outputArgs = (NET_VALIDATE_OUTPUT_ARG)Marshal.PtrToStructure(outputPointer, typeof(NET_VALIDATE_OUTPUT_ARG));
return outputArgs.ValidationStatus;
}
else
{
//fail
}
}
代码总是成功,为什么outputArgs.ValidationStatus 的值每次都是相同的结果,而不管 Active Directory 用户的状态如何?
【问题讨论】:
-
您在 ValidateCredentials() 之后尝试过 GetLastError() 吗?那么您可以使用错误代码来确定消息,例如 1907 是“用户必须重置密码”,1330 是“密码过期”等等......我可以考虑的另一个选项是 Logon 而不是 ValidateCredentials 然后GetLastError()
-
我查看了ValidateCredentials()的源码,该方法使用LADP,如果有错误代码该方法将抛出异常,然后捕获异常并返回false。所以 GetLastError 可能会起作用。我还看到活动目录有一些特殊的错误代码。
-
我们不想使用 LogonUser 方法,因为我们正在使用目录服务登录。如果用户输错密码,我们会尝试登录,失败,然后登录查看失败的原因。这将为用户的每次尝试提供两次失败的登录尝试。我将研究 GetLastError() 但 ValidateCredentials 每次都会返回 1907 并迫使开发人员查看 GetLastError() 以获取实际代码似乎很奇怪。
标签: c# com active-directory interop