512 c# authentication active-directory
如何针对Active Directory验证用户名和密码?我只是想检查用户名和密码是否正确.
mar*_*c_s 631
如果您使用的是.NET 3.5或更高版本,则可以使用System.DirectoryServices.AccountManagement命名空间并轻松验证您的凭据:
// 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");
}
Run Code Online (Sandbox Code Playgroud)
它很简单,可靠,它是你的100%C#托管代码 - 你还能要求什么?:-)
在这里阅读所有相关内容:
更新:
正如其他SO问题(及其答案)中所述,此调用可能会返回True用户的旧密码.只要注意这种行为,如果发生这种情况就不要太惊讶:-)(感谢@MikeGledhill指出这一点!)
Din*_*rer 68
我们在内联网上这样做
你必须使用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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
Sør*_*ors 57
此处介绍的几种解决方案无法区分错误的用户/密码和需要更改的密码.这可以通过以下方式完成:
using System;
using System.DirectoryServices.Protocols;
using System.Net;
namespace ProtocolTest
{
class Program
{
static void Main(string[] args)
{
try
{
LdapConnection connection = new LdapConnection("ldap.fabrikam.com");
NetworkCredential credential = new NetworkCredential("user", "password");
connection.Credential = credential;
connection.Bind();
Console.WriteLine("logged in");
}
catch (LdapException lexc)
{
String error = lexc.ServerErrorMessage;
Console.WriteLine(lexc);
}
catch (Exception exc)
{
Console.WriteLine(exc);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果用户密码错误,或者用户不存在,则会包含错误
"8009030C:LdapErr:DSID-0C0904DC,注释:AcceptSecurityContext错误,数据52e,v1db1",
如果需要更改用户密码,它将包含
"8009030C:LdapErr:DSID-0C0904DC,评论:AcceptSecurityContext错误,数据773,v1db1"
的lexc.ServerErrorMessage数据值是Win32错误代码的十六进制表示.这些是相同的错误代码,否则将通过调用Win32 LogonUser API调用返回.下面的列表总结了一系列带有十六进制和十进制值的常见值:
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)
Run Code Online (Sandbox Code Playgroud)
Ste*_*owe 34
使用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;
}
Run Code Online (Sandbox Code Playgroud)
需要NativeObject访问才能检测到错误的用户/密码
Ala*_*lan 28
遗憾的是,没有"简单"的方法来检查AD上的用户凭据.
对于到目前为止提出的每种方法,您可能会得到假阴性:用户的信用证有效,但在某些情况下AD将返回false:
ActiveDirectory不允许您使用LDAP来确定密码是否无效,因为用户必须更改密码或密码已过期.
要确定密码更改或密码已过期,您可以调用Win32:LogonUser(),并检查以下2个常量的Windows错误代码:
ste*_*hbu 21
可能最简单的方法是PInvoke LogonUser Win32 API.eg
MSDN参考这里......
绝对要使用登录类型
LOGON32_LOGON_NETWORK (3)
Run Code Online (Sandbox Code Playgroud)
这仅创建一个轻量级令牌 - 非常适合AuthN检查.(其他类型可用于构建交互式会话等)
Mat*_*cki 18
完整的.Net解决方案是使用System.DirectoryServices命名空间中的类.它们允许直接查询AD服务器.这是一个小样本,可以做到这一点:
using (DirectoryEntry entry = new DirectoryEntry())
{
entry.Username = "here goes the username you want to validate";
entry.Password = "here goes the password";
DirectorySearcher searcher = new DirectorySearcher(entry);
searcher.Filter = "(objectclass=user)";
try
{
searcher.FindOne();
}
catch (COMException ex)
{
if (ex.ErrorCode == -2147023570)
{
// Login or password is incorrect
}
}
}
// FindOne() didn't throw, the credentials are correct
Run Code Online (Sandbox Code Playgroud)
此代码使用提供的凭据直接连接到AD服务器.如果凭据无效,则searcher.FindOne()将抛出异常.ErrorCode是与"无效的用户名/密码"COM错误相对应的错误.
您不需要以AD用户身份运行代码.事实上,我成功地使用它来从域外的客户端查询AD服务器上的信息!
pal*_*wim 11
另一个.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
}
}
Run Code Online (Sandbox Code Playgroud)
Cha*_*ana 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
Run Code Online (Sandbox Code Playgroud)
除了你需要为"LogonException"创建自己的自定义异常
Windows 身份验证可能会因多种原因而失败:用户名或密码不正确、帐户锁定、密码过期等。要区分这些错误,请通过 P/Invoke 调用LogonUser API 函数,如果函数返回,请检查错误代码false:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
public static class Win32Authentication
{
private class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeTokenHandle() // called by P/Invoke
: base(true)
{
}
protected override bool ReleaseHandle()
{
return CloseHandle(this.handle);
}
}
private enum LogonType : uint
{
Network = 3, // LOGON32_LOGON_NETWORK
}
private enum LogonProvider : uint
{
WinNT50 = 3, // LOGON32_PROVIDER_WINNT50
}
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr handle);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool LogonUser(
string userName, string domain, string password,
LogonType logonType, LogonProvider logonProvider,
out SafeTokenHandle token);
public static void AuthenticateUser(string userName, string password)
{
string domain = null;
string[] parts = userName.Split('\\');
if (parts.Length == 2)
{
domain = parts[0];
userName = parts[1];
}
SafeTokenHandle token;
if (LogonUser(userName, domain, password, LogonType.Network, LogonProvider.WinNT50, out token))
token.Dispose();
else
throw new Win32Exception(); // calls Marshal.GetLastWin32Error()
}
}
Run Code Online (Sandbox Code Playgroud)
示例用法:
try
{
Win32Authentication.AuthenticateUser("EXAMPLE\\user", "P@ssw0rd");
// Or: Win32Authentication.AuthenticateUser("user@example.com", "P@ssw0rd");
}
catch (Win32Exception ex)
{
switch (ex.NativeErrorCode)
{
case 1326: // ERROR_LOGON_FAILURE (incorrect user name or password)
// ...
case 1327: // ERROR_ACCOUNT_RESTRICTION
// ...
case 1330: // ERROR_PASSWORD_EXPIRED
// ...
case 1331: // ERROR_ACCOUNT_DISABLED
// ...
case 1907: // ERROR_PASSWORD_MUST_CHANGE
// ...
case 1909: // ERROR_ACCOUNT_LOCKED_OUT
// ...
default: // Other
break;
}
}
Run Code Online (Sandbox Code Playgroud)
注意:LogonUser 需要与您正在验证的域建立信任关系。
小智 5
如果你坚持使用.NET 2.0和托管代码,这是另一种适用于本地和域帐户的方法:
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;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
445799 次 |
| 最近记录: |