首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何验证域凭据?

如何验证域凭据?
EN

Stack Overflow用户
提问于 2008-11-28 22:35:40
回答 5查看 129.1K关注 0票数 93

我想对域控制器验证一组凭据。例如:

代码语言:javascript
运行
复制
Username: STACKOVERFLOW\joel
Password: splotchy

方法1.模拟查询Active

很多人建议向Active Directory查询一些内容。如果引发异常,那么您就知道凭据无效-正如这个堆叠溢出问题中所建议的那样。

然而,有一些严重的这种方法的缺点

  1. 您不仅要对域帐户进行身份验证,而且还要进行隐式授权检查。也就是说,您正在使用模拟令牌从AD读取属性。如果其他有效帐户没有从AD读取的权限,该怎么办?默认情况下,所有用户都具有读取访问权限,但可以将域策略设置为禁用受限制帐户(或组)的访问权限。
  2. 与AD绑定有很大的开销,必须在客户端加载AD模式缓存(DirectoryServices使用的ADSI提供程序中的ADSI缓存)。这既是网络,也是AD服务器,消耗资源,而且对于简单的操作(比如验证用户帐户)来说太昂贵了。
  3. 对于非异常情况,您依赖于异常失败,并且假设这意味着用户名和密码无效。其他问题(如网络故障、AD连接失败、内存分配错误等)则被误认为是身份验证失败。

方法2. LogonUser Win32 API

其他建议使用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,但有些管理员可能会为每个人禁用它。

授予“作为操作系统一部分的行为”特权并不像微软在知识库文章中指出的那样,你不想故意这么做。

调用...the进程的LogonUser必须具有SE_TCB_NAME特权(在用户管理器中,这是“作为操作系统一部分的行为”的权限)。SE_TCB_NAME权限非常强大,不应该将授予任何任意用户,这样他们就可以运行需要验证凭据的应用程序

此外,如果指定了空白密码,则调用LogonUser()将失败。

验证一组域凭据的正确方法是什么?

我碰巧是从托管代码中调用的,但这是一个一般的Windows问题。可以假定客户已经安装了.NET Framework2.0。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2008-11-29 02:41:11

C#在.NET 3.5中使用System.DirectoryServices.AccountManagement

代码语言:javascript
运行
复制
 bool valid = false;
 using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
 {
     valid = context.ValidateCredentials( username, password );
 }

这将根据当前域进行验证。查看其他选项的参数化PrincipalContext构造函数。

票数 138
EN

Stack Overflow用户

发布于 2011-08-03 17:05:17

代码语言:javascript
运行
复制
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);
        }
    }
}
票数 22
EN

Stack Overflow用户

发布于 2014-11-06 17:33:44

我正在使用以下代码来验证凭据。下面显示的方法将确认凭据是否正确,如果不正确,密码是否过期或是否需要更改。

我已经找了这么久了.所以我希望这能帮上忙!

代码语言:javascript
运行
复制
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;
        }
    }
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/326818

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档