Как сделать сквозную авторизацию по имени пользователя в AD на компьютерах с Windows?
Пример: пользователь заходит в приложение, вводит имя пользователя и пароль AD и от сервера получает данные связанные с этой учетной записью
Как-то так:
//Reference: System.DirectoryServices.AccountManagement
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Security.Principal;
using System.DirectoryServices.AccountManagement;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace WindowsFormsApplication
{
static class Program
{
//Проверяет, авторизован ли пользователь в домене
public static bool IsInDomain(string domain)
{
bool retval = false;
NetJoinStatus status = NetJoinStatus.NetSetupUnknownStatus;
IntPtr pDomain = IntPtr.Zero;
int result = NetGetJoinInformation(null, out pDomain, out status);
if (result != 0) throw new Win32Exception("NetGetJoinInformation failed");
if (pDomain != IntPtr.Zero)
{
string curr_domain = Marshal.PtrToStringUni(pDomain);
if (status == NetJoinStatus.NetSetupDomainName &&
curr_domain.ToUpper().Trim() == domain.ToUpper().Trim())
{
retval = true;
}
NetApiBufferFree(pDomain);
}
return retval;
}
//Выводит диалоговое окно ввода логина и пароля, и возвращает имя пользователя при успешной авторизации
static string EnterCredentials(string domain)
{
bool save = false;
int errorcode = 0;
uint dialogReturn;
uint authPackage = 0;
IntPtr outCredBuffer;
uint outCredSize;
CREDUI_INFO credui = new CREDUI_INFO();
credui.cbSize = Marshal.SizeOf(credui);
credui.pszCaptionText = "Авторизация";
credui.pszMessageText = "Введите логин и пароль";
credui.hwndParent = IntPtr.Zero;
//Show dialog
dialogReturn = CredUIPromptForWindowsCredentials(ref credui,
errorcode, ref authPackage, (IntPtr)0, 0, out outCredBuffer, out outCredSize, ref save,
0x1 /*CREDUIWIN_GENERIC*/);
if (dialogReturn != 0) return ""; //Cancel pressed
var usernameBuf = new StringBuilder(100);
var passwordBuf = new StringBuilder(100);
var domainBuf = new StringBuilder(100);
int maxUserName = 100;
int maxDomain = 100;
int maxPassword = 100;
//Validate credentials
if (CredUnPackAuthenticationBuffer(0, outCredBuffer, outCredSize, usernameBuf,
ref maxUserName, domainBuf, ref maxDomain, passwordBuf, ref maxPassword))
{
CoTaskMemFree(outCredBuffer);
using (PrincipalContext context = new PrincipalContext(ContextType.Domain, domain))
{
bool valid;
valid = context.ValidateCredentials(usernameBuf.ToString(), passwordBuf.ToString());
if (valid) return usernameBuf.ToString();
else return "";
}
}
else throw new ApplicationException("CredUnPackAuthenticationBuffer failed");
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
string domain = "Domain";
string user = Environment.UserName;
bool logged = IsInDomain(domain);
if (logged)
{
MessageBox.Show("Здравствуйте, " + user + ". Вы уже авторизованы в " + domain);
}
else
{
user = EnterCredentials(domain);
if (user == "")
{
MessageBox.Show("Не удалось авторизоваться");
return;
}
else MessageBox.Show("Здравствуйте, " + user + ". Добро пожаловать в " + domain);
}
Application.Run(new Form1());
}
// *** WINAPI Functions ***
[DllImport("credui.dll", CharSet = CharSet.Unicode)]
private static extern uint CredUIPromptForWindowsCredentials(ref CREDUI_INFO notUsedHere,
int authError,
ref uint authPackage,
IntPtr InAuthBuffer,
uint InAuthBufferSize,
out IntPtr refOutAuthBuffer,
out uint refOutAuthBufferSize,
ref bool fSave,
uint flags);
[DllImport("credui.dll", CharSet = CharSet.Auto)]
private static extern bool CredUnPackAuthenticationBuffer(int dwFlags, IntPtr pAuthBuffer, uint cbAuthBuffer,
StringBuilder pszUserName, ref int pcchMaxUserName, StringBuilder pszDomainName,
ref int pcchMaxDomainame, StringBuilder pszPassword, ref int pcchMaxPassword
);
[DllImport("Netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int NetGetJoinInformation(string server, out IntPtr domain, out NetJoinStatus status);
[DllImport("Netapi32.dll")]
public static extern int NetApiBufferFree(IntPtr Buffer);
public enum NetJoinStatus
{
NetSetupUnknownStatus = 0,
NetSetupUnjoined,
NetSetupWorkgroupName,
NetSetupDomainName
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CREDUI_INFO
{
public int cbSize;
public IntPtr hwndParent;
public string pszMessageText;
public string pszCaptionText;
public IntPtr hbmBanner;
}
[DllImport("ole32.dll")]
public static extern void CoTaskMemFree(IntPtr ptr);
}
}
Источники
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
В чем дело?, я хочу добавить обработчик события из MainWindowxaml
Есть два метода которые я использую, и если я вызываю второй раз его прегрузку то выдает ошибку, ошибку напишу ниже Вот код методов