在Windows上使用本地用户账户实现基于表单的PHP身份验证

5

我正在使用PHP、Apache和Windows。由于我没有设置域名,因此我希望我的网站基于表单的身份验证可以使用Windows内置的本地用户账户数据库(我想它被称为SAM)。

我知道如果设置了Active Directory,您可以使用PHP LDAP模块连接并在脚本中进行身份验证,但是没有AD就没有LDAP。对于独立机器,有什么等效的方法吗?

3个回答

3

我也没有找到简单的解决方案。有一些例子使用CreateObject和WinNT ADSI提供程序。但最终它们都会遇到Active Directory Service Interfaces WinNT provider的用户身份验证问题。我不确定,但我猜WSH /网络连接方法也有同样的问题。
根据如何在Microsoft操作系统上验证用户凭据,您应该使用LogonUser或SSPI。
它还说

在Microsoft Windows Server 2003中,LogonUser Win32 API不需要TCB特权,但出于向下兼容性的考虑,这仍然是最佳途径。

在Windows XP上,进程不再需要具有SE_TCB_NAME特权才能调用LogonUser。因此,在Windows XP上验证用户凭据的最简单方法是调用LogonUser API。因此,如果我确定不需要Win9x/2000支持,我将编写一个扩展程序,将LogonUser暴露给php。
您可能还对NT帐户的用户身份验证感兴趣。它使用w32api扩展,并需要支持dll...我宁愿编写那个小的LogonUser扩展;-)
如果这不可行,我可能会研究IIS的fastcgi模块以及其稳定性,并让IIS处理身份验证。

编辑:
我也尝试使用System.Security.Principal.WindowsIdentity和php的com/.net扩展。但是dotnet构造函数似乎不允许将参数传递给对象构造函数,而从GetType()获取程序集(以及CreateInstance())的“实验”失败了,出现了“未知zval”错误。


0

构建PHP扩展需要相当大的硬盘空间投资。由于我已经安装了GCC(MinGW)环境,因此我决定承受从PHP脚本启动进程的性能损失。以下是源代码。

// Usage: logonuser.exe /user username /password password [/domain domain]
// Exit code is 0 on logon success and 1 on failure.

#include <windows.h>

int main(int argc, char *argv[]) {
    HANDLE r = 0;
    char *user = 0;
    char *password = 0;
    char *domain = 0;
    int i;

    for(i = 1; i < argc; i++) {
        if(!strcmp(argv[i], "/user")) {
            if(i + 1 < argc) {
                user = argv[i + 1];
                i++;
            }
        } else if(!strcmp(argv[i], "/domain")) {
            if(i + 1 < argc) {
                domain = argv[i + 1];
                i++;
            }
        } else if(!strcmp(argv[i], "/password")) {
            if(i + 1 < argc) {
                password = argv[i + 1];
                i++;
            }
        }
    }

    if(user && password) {
        LogonUser(user, domain, password, LOGON32_LOGON_BATCH, LOGON32_PROVIDER_DEFAULT, &r);
    }
    return r ? 0 : 1;
}

Next is the PHP source demonstrating its use.

if($_SERVER['REQUEST_METHOD'] == 'POST') {
    if(isset($_REQUEST['user'], $_REQUEST['password'], $_REQUEST['domain'])) {
        $failure = 1;
        $user = $_REQUEST['user'];
        $password = $_REQUEST['password'];
        $domain = $_REQUEST['domain'];

        if($user && $password) {
            $cmd = "logonuser.exe /user " . escapeshellarg($user) . " /password " . escapeshellarg($password);
            if($domain) $cmd .= " /domain " . escapeshellarg($domain);
            system($cmd, $failure);
        }

        if($failure) {
            echo("Incorrect credentials.");
        } else {
            echo("Correct credentials!");
        }
    }
}
?>
<form action="<?php echo(htmlentities($_SERVER['PHP_SELF'])); ?>" method="post">
    Username: <input type="text" name="user" value="<?php echo(htmlentities($user)); ?>" /><br />
    Password: <input type="password" name="password" value="" /><br />
    Domain: <input type="text" name="domain" value="<?php echo(htmlentities($domain)); ?>" /><br />
    <input type="submit" value="logon" />
</form>


0

好问题!

我认真思考了一下,但是我找不到一个好的解决方案。我只能想到一个可怕的 hack 方法,它可能会奏效。看到没有人在近一天内对这个问题发表答案,我觉得一个糟糕但可行的答案应该可以。

系统运行时,SAM 文件是不可访问的。有一些 DLL 注入技巧,也许你可以让它们工作,但最终你只会得到密码哈希值,而且你必须对用户提供的密码进行哈希以与之匹配。

你真正想要的是尝试使用 SAM 文件对用户进行身份验证。我认为你可以通过以下方式实现:

  1. 在服务器上创建文件共享,并将其配置为仅授权要登录的账户访问。
  2. 在 PHP 中使用 system 命令调用 wsh 脚本:使用网站用户提供的用户名和密码挂载共享,记录结果,然后卸载驱动器(如果成功的话)。
  3. 某种方式收集结果。结果可以通过脚本的 stdout 或者希望获得脚本返回代码的方式返回给 PHP。

我知道它不太好看,但应该能用。

我感觉很不舒服 :|

编辑:调用外部wsh脚本的原因是PHP不允许使用UNC路径(据我所记)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接