我想针对域控制器验证一组凭据 . 例如 . :
Username: STACKOVERFLOW\joel
Password: splotchy
方法1.使用模拟查询Active Directory
很多人建议查询Active Directory . 如果抛出异常,则表示凭据无效 - 如this stackoverflow question中所述 .
然而,有一些严重的drawbacks to this approach:
-
您不仅要对域帐户进行身份验证,还要进行隐式授权检查 . 也就是说,您正在使用模拟令牌从AD中读取属性 . 如果其他有效帐户无权从AD读取,该怎么办?默认情况下,所有用户都具有读取权限,但可以将域策略设置为禁用受限帐户(和/或组)的访问权限 .
-
绑定AD会产生严重的开销,必须在客户端加载AD架构缓存(DirectoryServices使用的ADSI提供程序中的ADSI缓存) . 这既是网络又是AD服务器,消耗资源 - 而且对于像验证用户帐户这样的简单操作来说太昂贵了 .
-
您依赖于非例外情况的异常失败,并假设这意味着无效的用户名和密码 . 然后,其他问题(例如,网络故障,AD连接故障,内存分配错误等)被错误地表示为身份验证失败 .
方法2. LogonUser Win32 API
Others建议使用LogonUser() API函数 . 这听起来不错,但不幸的是,调用用户有时需要一个权限,通常只给操作系统本身:
调用LogonUser的进程需要SE_TCB_NAME权限 . 如果调用进程没有此权限,LogonUser将失败,GetLastError将返回ERROR_PRIVILEGE_NOT_HELD . 在某些情况下,调用LogonUser的进程还必须启用SE_CHANGE_NOTIFY_NAME权限;否则,LogonUser失败,GetLastError返回ERROR_ACCESS_DENIED . 作为管理员组成员的本地系统帐户或帐户不需要此权限 . 默认情况下,为所有用户启用SE_CHANGE_NOTIFY_NAME,但某些管理员可能会为所有用户禁用它 .
正如微软在_2486560中指出的那样,发布“作为操作系统的一部分”特权并不是你想要做的事情 .
...调用LogonUser的进程必须具有SE_TCB_NAME权限(在用户管理器中,这是“作为操作系统的一部分”权限) . SE_TCB_NAME权限非常强大,不应授予任何任意用户,以便他们可以运行需要验证凭据的应用程序 .
此外,如果指定了空密码,则对 LogonUser()
的调用将失败 .
验证一组域凭据的正确方法是什么?
我碰巧是从托管代码调用,但这是一个普通的Windows问题 . 可以假设客户已安装.NET Framework 2.0 .
5 回答
.NET 3.5中的C#使用System.DirectoryServices.AccountManagement .
这将验证当前域 . 查看参数化的PrincipalContext构造函数以获取其他选项 .
我使用以下代码来验证凭据 . 下面显示的方法将确认凭据是否正确,如果密码已过期或需要更改 .
我一直在寻找这样的东西...所以我希望这有助于某人!
以下是如何确定本地用户:
由Ian Boyd编辑
你不应该再使用NTLM了 . 微软的应用程序验证程序(用于捕获常见的编程错误)如果它检测到你使用NTLM就会发出警告,这是如此古老,如此糟糕 .
以下是Application Verifier文档中的一章,说明如果有人错误地使用NTLM,他们为什么要进行测试:
Kashif Mushtaq渥太华,加拿大