Какую версию Windows вы используете (7 или 10)?
Эта проблема, по-видимому, относится к привилегии пользователя ... и если она похожа на эту проблему , сначала попробуйте запустить файл exe с правами администратора, а если он снова исчезнет, попробуйте запустить «Pyinstaller» из cmd.exe , работающего с правами администратора.
К сожалению, нет простого способа проверить учетные данные пользователей в AD.
С каждым представленным до сих пор способом вы можете получить ложно-отрицательный: будут введены пользовательские creds, однако AD вернет false при определенных обстоятельствах:
ActiveDirectory не позволит вам использовать LDAP для определения того, является ли пароль недопустимым из-за того, что пользователь должен сменить пароль или срок их пароля истек.
Чтобы определить изменение пароля или пароль истек, вы можете позвонить Win32: LogonUser () и проверьте код ошибки Windows для следующих 2 констант:
Попробуйте этот код (ПРИМЕЧАНИЕ: Сообщается, что он не работает на сервере Windows 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
, за исключением того, что вам нужно создать собственное собственное исключение для «LogonException»
Если вы застряли с .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;
}
В нескольких представленных здесь решениях нет возможности различать неправильный пользователь / пароль и пароль, который необходимо изменить. Это может быть сделано следующим образом:
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);
}
}
}
}
Если пароль пользователя неверен или пользователь не существует, ошибка будет содержать
"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)
System.DirectoryServices
и System.DirectoryServices.Protocols
– TomXP411
4 April 2013 в 23:46
Мы делаем это на нашей интрасети
. Вы должны использовать 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();
}
}
}
UserPrinciple.FindByIdentity
, чтобы узнать, существует ли ранее установленный идентификатор пользователя.
– Chris J
8 September 2011 в 16:17
ContextOptions.Negotiate
.
– Brett Veenstra
20 September 2011 в 23:37
Close()
переменной using
.
– Nyerguds
17 May 2016 в 09:28
Моя простая функция
private bool IsValidActiveDirectoryUser(string activeDirectoryServerDomain, string username, string password)
{
try
{
DirectoryEntry de = new DirectoryEntry("LDAP://" + activeDirectoryServerDomain, username + "@" + activeDirectoryServerDomain, password, AuthenticationTypes.Secure);
DirectorySearcher ds = new DirectorySearcher(de);
ds.FindOne();
return true;
}
catch //(Exception ex)
{
return false;
}
}
очень простое решение с использованием 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 необходим для обнаружения плохих пользователей / паролей
PrincipleContext
- который существует только в .NET 3.5. Но если вы используете .NET 3.5 или новее, вы должны использовать PrincipleContext
– Ian Boyd
18 August 2011 в 17:57
Полное решение .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
Этот код напрямую подключается к серверу AD, используя предоставленные учетные данные. Если учетные данные недействительны, искатель.FindOne () выдаст исключение. ErrorCode - это тот, который соответствует ошибке COM с недопустимым именем пользователя / паролем.
Вам не нужно запускать код как пользователь AD. Фактически, я успешно использую его для запроса информации на сервере AD, от клиента за пределами домена!
Проверка подлинности Windows может произойти по различным причинам: неправильное имя пользователя или пароль, заблокированная учетная запись, истекший пароль и т. д. Чтобы различать эти ошибки, вызовите функцию API LogonUser через P / Invoke и проверьте код ошибки, если функция возвращает 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()
}
}
Использование примера:
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;
}
}
Примечание: для входа в LogonUser требуется доверительное отношение с доменом, который вы проверяете.
Еще один вызов .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
}
}
Вероятно, самый простой способ - PInvoke LogonUser Win32 API.eg
http://www.pinvoke.net/default.aspx/advapi32/LogonUser.html
blockquote>Ссылка на MSDN здесь ...
http://msdn.microsoft.com/en-us/library/aa378184.aspx
blockquote>Определенно хотите использовать тип входа
LOGON32_LOGON_NETWORK (3)
Это создает только легкий токен - идеально подходит для проверок AuthN. (другие типы могут использоваться для создания интерактивных сеансов и т. д.).
LogonUser
требует, чтобы пользователь имел Act как часть операционной системы privelage; которые не получают пользователи, а не то, что вы хотите предоставить каждому пользователю в организации. ( msdn.microsoft.com/en-us/library/aa378184 (v = vs.85) .aspx [/ д0])
– Ian Boyd
18 August 2011 в 14:52