使用PrincipalContext时出错.validatecredential根据本地机器进行身份验证
本文关键字:机器 身份验证 PrincipalContext 出错 validatecredential 使用 | 更新日期: 2023-09-27 18:05:39
我有一个WCF服务,其中包含一个Login
方法,该方法根据本地计算机凭据验证用户名和密码,并且在看似随机的一段时间后,它将停止为某些用户工作。
实际的登录命令如下所示:
public UserModel Login(string username, string password, string ipAddress)
{
// Verify valid parameters
if (username == null || password == null)
return null;
try
{
using (var pContext = new PrincipalContext(ContextType.Machine))
{
// Authenticate against local machine
if (pContext.ValidateCredentials(username, password))
{
// Authenticate user against database
using (var context = new MyEntities(Connections.GetConnectionString()))
{
var user = (from u in context.Users
where u.LoginName.ToUpper() == username.ToUpper()
&& u.IsActive == true
&& (string.IsNullOrEmpty(u.AllowedIpAddresses)
|| u.AllowedIpAddresses.Contains(ipAddress))
select u).FirstOrDefault();
// If user failed to authenticate against database
if (user == null)
return null;
// Map entity object to return object and assign session token
var userModel = Mapper.Map<User, UserModel>(user);
userModel.Token = Guid.NewGuid();
userModel.LastActivity = DateTime.Now;
// Authenticated users are added to a list on the server
// and their login expires after 20 minutes of inactivity
authenticatedUsers.Add(userModel);
sessionTimer.Start();
// User successfully authenticated, so return UserModel to client
return userModel;
}
}
}
}
catch(Exception ex)
{
// This is getting hit
MessageLog.WriteMessage(string.Format("Exception occurred while validating user: {0}'n{1}", ex.Message, ex.StackTrace));
return null;
}
// If authentication against local machine failed, return null
return null;
}
这在几天内似乎可以正常工作,然后它会突然停止工作,并抛出以下异常:
不允许同一用户使用多个用户名连接到服务器或共享资源。断开以前与服务器或共享资源的所有连接,然后重试。(Exception from HRESULT: 0x800704C3)
在System.DirectoryServices.AccountManagement.CredentialValidator。BindSam(字符串目标,字符串用户名,字符串密码)
在System.DirectoryServices.AccountManagement.CredentialValidator。验证(字符串userName,字符串password)
在System.DirectoryServices.AccountManagement.PrincipalContext。validatecredals (String userName, String password)
在MyNamespace.LoginService。Login(String username, String password, String ipAddress) in C:'Users'me'Desktop'somefolder'LoginService.svc.cs:line 67
第67行:if (pContext.ValidateCredentials(username, password))
我不确定它是否重要,但错误消息的最后一行是我的开发机器上的VS解决方案的路径,而不是生产服务器上的文件路径。
当它失败时,它只对某些用户失败,而其他用户可以继续正常登录。我发现暂时修复错误的唯一方法是运行iisreset
。停止/启动网站或回收应用程序池不起作用。
我无法按要求重现错误。我试过从多个会话和IP地址登录同一用户,从同一浏览器会话登录不同的用户在同一时间,垃圾邮件登录按钮,试图让它运行多次,等,但一切似乎都很好。
我可以从我们的日志中看到用户过去已经成功登录:
<>之前3/21/20139:03 . a我登录了0 1:54p用户b登录0 1:55p用户登录o 2:38p用户b登录o 3:48p用户b登录5点18分用户登录o 6:11p用户b登录3/22/2013[12:42 . 02]用户登录o 5:22p用户b登录08:04 p用户b登录3/25/2013(今天)8:47a我登录了o 12:38p用户b尝试登录,失败。在接下来的45分钟内重复~15次1:58我登录成功0 2:08p我尝试登录与用户b的登录信息,失败与同样的错误之前我们对本地机器进行身份验证的原因是用户在本地创建了一个用于FTP访问的帐户,我们不想构建自己的自定义登录系统或让用户记住两组凭据。
代码应该只验证用户的凭据,而不对用户的凭据做任何其他事情。没有其他代码使用System.DirectoryServices
,没有文件IO正在进行,并且除了运行web应用程序所需的文件之外,不能访问文件系统上的任何本地内容。
是什么导致这个错误在几天后出现,似乎是随机的?我该怎么补救呢?
服务器是Windows server 2003,运行IIS 6.0,并设置为使用。net Framework 4.0
我能在网上找到最接近解释这个问题的是这个论坛帖子,用户遇到同样的错误,并得到重播声明:
WinNT提供程序在服务器环境中不能很好地工作。我是实际上很惊讶你没有在更小的负载上看到这个。我有只有2到3个用户就能得到这个。
和这个SO注释说明
正确验证某人的最佳方法是使用LogonUserAPI正如@stephbu所写。这篇文章中描述的所有其他方法都不会工作100%
其中"所有其他方法"包括使用PrincipalContext.ValidateCredentials
的最高投票答案
听起来像PrincipalContext.ValidateCredentials
在Windows Server 2003和IIS6.0上不是完全100%可靠,所以我重写了我的身份验证代码,使用LogonUser WinAPI方法代替。
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(
string lpszUsername,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
out IntPtr phToken
);
IntPtr hToken;
if (LogonUser(username, "", password,
LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, out hToken))
{
...
}