2013-03-25 87 views
10

我有一个WCF服务,其中包含一个Login方法,该方法根据本地机器凭据验证用户名和密码,并且在看似随机的一段时间后,它将停止对某些用户工作。使用PrincipalContext.ValidateCredentials对本地计算机进行身份验证时出错?

实际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; 
} 

这似乎几天做工精细,然后它会突然停止对一些用户的工作,并抛出这个异常:

不允许同一用户使用多个用户名连接到服务器或共享资源。断开以前与服务器或共享资源的所有连接,然后重试。 (从HRESULT异常:0x800704C3)

在System.DirectoryServices.AccountManagement.CredentialValidator.BindSam(字符串对象,用户名字符串,字符串密码)

在System.DirectoryServices.AccountManagement.CredentialValidator.Validate(用户名字符串,串密码)

在用C System.DirectoryServices.AccountManagement.PrincipalContext.ValidateCredentials(用户名字符串,字符串密码)

在MyNamespace.LoginService.Login(字符串username,字符串密码,串ip地址):\用户\米Ë\桌面\ somefolder \ LoginService.svc.cs:行67

第67行是:if (pContext.ValidateCredentials(username, password))

我不知道,如果它的事项或没有,但错误信息的最后一行是我的开发机器上VS解决方案的路径,而不是生产服务器上文件的路径。

当它失败时,它只对某些用户失败,而其他用户可以继续登录。我发现暂时修复错误的唯一方法是运行iisreset。停止/启动网站或回收应用程序池不起作用。

我无法按需重现错误。我试着用同一个用户从多个会话和IP地址登录,同时在同一个浏览器会话中用不同的用户登录,发送登录按钮尝试让它运行多次等等,但是一切都出现了工作正常。

我可以从我们的记录看到,用户已经能够成功在过去的登录:

 
3/21/2013 
o 9:03a I logged in 
o 1:54p UserB logged in 
o 1:55p UserA logged in 
o 2:38p UserB logged in 
o 3:48p UserB logged in 
o 5:18p UserA logged in 
o 6:11p UserB logged in 

3/22/2013 
o 12:42p UserA logged in 
o 5:22p UserB logged in 
o 8:04p UserB logged in 

3/25/2013 (today) 
o 8:47a I logged in 
o 12:38p UserB tries logging in and fails. Repeated ~15 times over next 45 min 
o 1:58p I login successfully 
o 2:08p I try to login with UserB's login info and fail with the same error 

我们针对本地计算机进行身份验证的原因是因为用户在本地FTP访问创建一个帐户,我们不想构建自己的自定义登录系统或让我们的用户记住两组凭证。

该代码应该只验证用户的凭据,并且不会对用户凭证做任何其他操作。没有其他代码使用System.DirectoryServices,没有文件IO继续进行,除了运行Web应用程序所需的文件之外,不能在文件系统上本地访问任何内容。

什么会导致错误在几天之后出现,看似随机?我该如何解决它?

服务器是Windows Server 2003中,它运行IIS 6.0,它是设置为使用.Net框架4.0

回答

4

我能找到的最接近的在线地解释了这个问题this forum post,当用户遇到了同样的错误并得到一个重播:

WinNT提供程序在服务器环境中表现不佳。实际上我很惊讶,你没有看到这个小得多的负载。我有 只有2或3个用户能够得到这个。

this SO comment说明

要正确验证某人的最好办法是使用LogonUserAPI 作为@stephbu写。在这篇文章中描述的所有其他方法将无法 工作100%

其中“其他方法”包含顶级投用PrincipalContext.ValidateCredentials

它听起来像PrincipalContext.ValidateCredentials的答案不是Windows完全100%可靠Server 2003和IIS6.0,所以我重写了我的身份验证代码,以代替使用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)) 
{ 
    ... 
} 
+0

我浪费了几个小时,谢谢rachel, – 2017-01-16 07:21:57

相关问题