Ian*_*oyd 79 c# windows security authentication
我想针对域控制器验证一组凭据.例如:
Username: STACKOVERFLOW\joel
Password: splotchy
Run Code Online (Sandbox Code Playgroud)
很多人建议查询Active Directory.如果抛出异常,那么您知道凭据无效 - 正如此stackoverflow问题中所建议的那样.
您不仅要对域帐户进行身份验证,还要进行隐式授权检查.也就是说,您正在使用模拟令牌从AD中读取属性.如果其他有效帐户无权从AD读取,该怎么办?默认情况下,所有用户都具有读取权限,但可以将域策略设置为禁用受限帐户(和/或组)的访问权限.
绑定AD会产生严重的开销,必须在客户端加载AD架构缓存(DirectoryServices使用的ADSI提供程序中的ADSI缓存).这既是网络又是AD服务器,消耗资源 - 而且对于像验证用户帐户这样的简单操作来说太昂贵了.
您依赖于非例外情况的异常失败,并假设这意味着无效的用户名和密码.然后,其他问题(例如,网络故障,AD连接故障,内存分配错误等)被错误地表示为身份验证失败.
其他人建议使用LogonUser()
API函数.这听起来不错,但不幸的是,调用用户有时需要一个权限,通常只给操作系统本身:
调用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权限(在用户管理器中,这是" 作为操作系统的一部分 "权限).SE_TCB_NAME权限非常强大, 不应授予任何任意用户,以便他们可以运行需要验证凭据的应用程序.
此外,LogonUser()
如果指定了空密码,则调用将失败.
验证一组域凭据的正确方法是什么?
我碰巧是从托管代码调用,但这是一个普通的Windows问题.可以假设客户已安装.NET Framework 2.0.
tva*_*son 122
.NET 3.5中的C#使用System.DirectoryServices.AccountManagement.
bool valid = false;
using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
{
valid = context.ValidateCredentials( username, password );
}
Run Code Online (Sandbox Code Playgroud)
这将验证当前域.查看参数化的PrincipalContext构造函数以获取其他选项.
小智 19
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security;
using System.DirectoryServices.AccountManagement;
public struct Credentials
{
public string Username;
public string Password;
}
public class Domain_Authentication
{
public Credentials Credentials;
public string Domain;
public Domain_Authentication(string Username, string Password, string SDomain)
{
Credentials.Username = Username;
Credentials.Password = Password;
Domain = SDomain;
}
public bool IsValid()
{
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, Domain))
{
// validate the credentials
return pc.ValidateCredentials(Credentials.Username, Credentials.Password);
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 6
我使用以下代码来验证凭据.下面显示的方法将确认凭据是否正确,如果密码已过期或需要更改.
我一直在寻找这样的东西...所以我希望这有助于某人!
using System;
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;
using System.Runtime.InteropServices;
namespace User
{
public static class UserValidation
{
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool LogonUser(string principal, string authority, string password, LogonTypes logonType, LogonProviders logonProvider, out IntPtr token);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr handle);
enum LogonProviders : uint
{
Default = 0, // default for platform (use this!)
WinNT35, // sends smoke signals to authority
WinNT40, // uses NTLM
WinNT50 // negotiates Kerb or NTLM
}
enum LogonTypes : uint
{
Interactive = 2,
Network = 3,
Batch = 4,
Service = 5,
Unlock = 7,
NetworkCleartext = 8,
NewCredentials = 9
}
public const int ERROR_PASSWORD_MUST_CHANGE = 1907;
public const int ERROR_LOGON_FAILURE = 1326;
public const int ERROR_ACCOUNT_RESTRICTION = 1327;
public const int ERROR_ACCOUNT_DISABLED = 1331;
public const int ERROR_INVALID_LOGON_HOURS = 1328;
public const int ERROR_NO_LOGON_SERVERS = 1311;
public const int ERROR_INVALID_WORKSTATION = 1329;
public const int ERROR_ACCOUNT_LOCKED_OUT = 1909; //It gives this error if the account is locked, REGARDLESS OF WHETHER VALID CREDENTIALS WERE PROVIDED!!!
public const int ERROR_ACCOUNT_EXPIRED = 1793;
public const int ERROR_PASSWORD_EXPIRED = 1330;
public static int CheckUserLogon(string username, string password, string domain_fqdn)
{
int errorCode = 0;
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, domain_fqdn, "ADMIN_USER", "PASSWORD"))
{
if (!pc.ValidateCredentials(username, password))
{
IntPtr token = new IntPtr();
try
{
if (!LogonUser(username, domain_fqdn, password, LogonTypes.Network, LogonProviders.Default, out token))
{
errorCode = Marshal.GetLastWin32Error();
}
}
catch (Exception)
{
throw;
}
finally
{
CloseHandle(token);
}
}
}
return errorCode;
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
109370 次 |
最近记录: |