我想针对域控制器验证一组凭据。例如:
Username: STACKOVERFLOW\joel Password: splotchy
很多人建议在Active Directory中查询某些内容。如果抛出异常,则说明凭据无效-如本stackoverflow问题所示。
但是,这种方法有一些严重的缺点:
您不仅在验证域帐户,而且还在进行隐式授权检查。也就是说,您正在使用模拟令牌从AD读取属性。如果原本有效的帐户无权读取广告怎么办?默认情况下,所有用户都具有读取访问权限,但是可以将域策略设置为禁用受限帐户(和/或组)的访问权限。
与AD绑定会产生严重的开销,必须在客户端上加载AD模式缓存(DirectoryServices使用的ADSI提供程序中的ADSI缓存)。这既是网络,又是AD服务器,都非常耗资源-对于简单的操作(如验证用户帐户)而言,费用太高。
对于非例外情况,您要依靠例外失败,并假设这意味着无效的用户名和密码。其他问题(例如,网络故障,AD连接故障,内存分配错误等)随后会误认为身份验证失败。
其他人建议使用LogonUser()API函数。这听起来不错,但不幸的是,调用用户有时有时需要通常仅授予操作系统本身的权限:
LogonUser()
调用LogonUser的进程需要SE_TCB_NAME特权。如果调用过程没有此特权,则LogonUser失败,并且GetLastError返回ERROR_PRIVILEGE_NOT_HELD。 在某些情况下,调用LogonUser的过程还必须启用SE_CHANGE_NOTIFY_NAME特权;否则,LogonUser失败,并且GetLastError返回ERROR_ACCESS_DENIED。本地系统帐户或属于管理员组的帐户不需要此特权。默认情况下,SE_CHANGE_NOTIFY_NAME为所有用户启用,但是某些管理员可能为所有人禁用它。
调用LogonUser的进程需要SE_TCB_NAME特权。如果调用过程没有此特权,则LogonUser失败,并且GetLastError返回ERROR_PRIVILEGE_NOT_HELD。
在某些情况下,调用LogonUser的过程还必须启用SE_CHANGE_NOTIFY_NAME特权;否则,LogonUser失败,并且GetLastError返回ERROR_ACCESS_DENIED。本地系统帐户或属于管理员组的帐户不需要此特权。默认情况下,SE_CHANGE_NOTIFY_NAME为所有用户启用,但是某些管理员可能为所有人禁用它。
发放“ 充当操作系统的一部分 ”特权并不是您要随意地做的事- 正如Microsoft在知识库文章中指出的那样:
…正在调用LogonUser的进程必须具有SE_TCB_NAME特权(在用户管理器中,这是“ 充当操作系统的一部分 ”权限)。SE_TCB_NAME特权非常强大, 不应仅授予任意用户一个 特权 ,以便他们可以运行 需要验证凭据 的应用程序 。
此外,LogonUser()如果指定了空白密码,则对的调用将失败。
验证一组域凭据的正确方法是什么?
我 碰巧 是从托管代码调用的,但这是Windows的一个普遍问题。可以假定客户安装了.NET Framework 2.0。
使用System.DirectoryServices.AccountManagement的 .NET 3.5中的C#。
bool valid = false; using (PrincipalContext context = new PrincipalContext(ContextType.Domain)) { valid = context.ValidateCredentials( username, password ); }
这将针对当前域进行验证。检出参数化的PrincipalContext构造函数以获取其他选项。