525 user not found (1317)
52e invalid credentials (1326)
530 not permitted to logon at this time (1328)
531 not permitted to logon at this workstation (1329)
532 password expired (1330)
533 account disabled (1331)
701 account expired (1793)
773 user must reset password (1907)
775 user account locked (1909)
62
使用DirectoryServices的非常简单的解决方案:
using System.DirectoryServices;
//srvr = ldap server, e.g. LDAP://domain.com
//usr = user name
//pwd = user password
public bool IsAuthenticated(string srvr, string usr, string pwd)
{
bool authenticated = false;
try
{
DirectoryEntry entry = new DirectoryEntry(srvr, usr, pwd);
object nativeObject = entry.NativeObject;
authenticated = true;
}
catch (DirectoryServicesCOMException cex)
{
//not authenticated; reason why is in cex
}
catch (Exception ex)
{
//not authenticated due to some other exception [this is optional]
}
return authenticated;
}
需要NativeObject访问才能检测到错误的用户/密码
48
另一个.NET调用快速验证LDAP凭据:
using System.DirectoryServices;
using(var DE = new DirectoryEntry(path, username, password)
{
try
{
DE.RefreshCache(); // This will force credentials validation
}
catch (COMException ex)
{
// Validation failed - handle how you want
}
}
0
我们在内联网上这样做
你必须使用System.DirectoryServices;
以下是代码的内容
using (DirectoryEntry adsEntry = new DirectoryEntry(path, strAccountId, strPassword))
{
using (DirectorySearcher adsSearcher = new DirectorySearcher(adsEntry))
{
//adsSearcher.Filter = "(&(objectClass=user)(objectCategory=person))";
adsSearcher.Filter = "(sAMAccountName=" + strAccountId + ")";
try
{
SearchResult adsSearchResult = adsSearcher.FindOne();
bSucceeded = true;
strAuthenticatedBy = "Active Directory";
strError = "User has been authenticated by Active Directory.";
}
catch (Exception ex)
{
// Failed to authenticate. Most likely it is caused by unknown user
// id or bad strPassword.
strError = ex.Message;
}
finally
{
adsEntry.Close();
}
}
}
// create a "principal context" - e.g. your domain (could be machine, too)
using(PrincipalContext pc = new PrincipalContext(ContextType.Domain, "YOURDOMAIN"))
{
// validate the credentials
bool isValid = pc.ValidateCredentials("myuser", "mypassword");
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Security;
using System.Diagnostics;
static public bool Validate(string domain, string username, string password)
{
try
{
Process proc = new Process();
proc.StartInfo = new ProcessStartInfo()
{
FileName = "no_matter.xyz",
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true,
RedirectStandardInput = true,
LoadUserProfile = true,
Domain = String.IsNullOrEmpty(domain) ? "" : domain,
UserName = username,
Password = Credentials.ToSecureString(password)
};
proc.Start();
proc.WaitForExit();
}
catch (System.ComponentModel.Win32Exception ex)
{
switch (ex.NativeErrorCode)
{
case 1326: return false;
case 2: return true;
default: throw ex;
}
}
catch (Exception ex)
{
throw ex;
}
return false;
}
10
试试这段代码(注意:报告不能在Windows Server 2000上运行)
#region NTLogonUser
#region Direct OS LogonUser Code
[DllImport( "advapi32.dll")]
private static extern bool LogonUser(String lpszUsername,
String lpszDomain, String lpszPassword, int dwLogonType,
int dwLogonProvider, out int phToken);
[DllImport("Kernel32.dll")]
private static extern int GetLastError();
public static bool LogOnXP(String sDomain, String sUser, String sPassword)
{
int token1, ret;
int attmpts = 0;
bool LoggedOn = false;
while (!LoggedOn && attmpts < 2)
{
LoggedOn= LogonUser(sUser, sDomain, sPassword, 3, 0, out token1);
if (LoggedOn) return (true);
else
{
switch (ret = GetLastError())
{
case (126): ;
if (attmpts++ > 2)
throw new LogonException(
"Specified module could not be found. error code: " +
ret.ToString());
break;
case (1314):
throw new LogonException(
"Specified module could not be found. error code: " +
ret.ToString());
case (1326):
// edited out based on comment
// throw new LogonException(
// "Unknown user name or bad password.");
return false;
default:
throw new LogonException(
"Unexpected Logon Failure. Contact Administrator");
}
}
}
return(false);
}
#endregion Direct Logon Code
#endregion NTLogonUser
12 回答
我的简单功能
此处介绍的几种解决方案无法区分错误的用户/密码和需要更改的密码 . 这可以通过以下方式完成:
如果用户密码错误,或者用户不存在,则会包含错误
“8009030C:LdapErr:DSID-0C0904DC,注释:AcceptSecurityContext错误,数据52e,v1db1”,
如果需要更改用户密码,它将包含
“8009030C:LdapErr:DSID-0C0904DC,注释:AcceptSecurityContext错误,数据773,v1db1”
lexc.ServerErrorMessage
数据值是Win32错误代码的十六进制表示形式 . 这些是相同的错误代码,否则将通过调用Win32 LogonUser API调用返回 . 下面的列表总结了一系列带有十六进制和十进制值的常见值:使用DirectoryServices的非常简单的解决方案:
需要NativeObject访问才能检测到错误的用户/密码
另一个.NET调用快速验证LDAP凭据:
我们在内联网上这样做
你必须使用System.DirectoryServices;
以下是代码的内容
如果您使用的是.NET 3.5或更高版本,则可以使用
System.DirectoryServices.AccountManagement
命名空间并轻松验证您的凭据:它很简单,可靠,它是你的100%C#托管代码 - 你还能要求什么? :-)
在这里阅读所有相关内容:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
Update:
如this other SO question (and its answers)中所述,此调用可能会返回
True
用于用户的旧密码 . 只要注意这种行为,如果发生这种情况就不要太惊讶:-)(感谢@MikeGledhill指出这一点!)遗憾的是,没有“简单”的方法来检查AD上的用户凭据 .
对于目前为止提出的每种方法,您可能会得到假阴性:用户的信用证有效,但在某些情况下AD会返回false:
用户需要在下次登录时更改密码 .
用户密码已过期 .
ActiveDirectory不允许您使用LDAP来确定密码是否无效,因为用户必须更改密码或密码已过期 .
要确定密码更改或密码已过期,您可以调用Win32:LogonUser(),并检查以下2个常量的Windows错误代码:
ERROR_PASSWORD_MUST_CHANGE = 1907
ERROR_PASSWORD_EXPIRED = 1330
如果你坚持使用.NET 2.0和托管代码,这是另一种适用于本地和域帐户的方法:
试试这段代码(注意:报告不能在Windows Server 2000上运行)
除了你需要为“LogonException”创建自己的自定义异常
完整的.Net解决方案是使用System.DirectoryServices命名空间中的类 . 它们允许直接查询AD服务器 . 这是一个小样本,可以这样做:
此代码使用提供的凭据直接连接到AD服务器 . 如果凭据无效,searcher.FindOne()将抛出异常 . ErrorCode是与“无效的用户名/密码”COM错误相对应的错误 .
您不需要以AD用户身份运行代码 . 事实上,我成功地使用它来从域外的客户端查询AD服务器上的信息!
可能最简单的方法是PInvoke LogonUser Win32 API.e.g.
MSDN参考这里......
绝对要使用登录类型
这仅创建一个轻量级令牌 - 非常适合AuthN检查 . (其他类型可用于构建交互式会话等)
Windows身份验证可能由于各种原因而失败:错误的用户名或密码,锁定的帐户,过期的密码等 . 要区分这些错误,请通过P / Invoke调用LogonUser API函数,如果函数返回
false
,则检查错误代码:样品用法:
注意:LogonUser需要与您要验证的域之间存在信任关系 .