我正在使用PHP、Apache和Windows。由于我没有设置域名,因此我希望我的网站基于表单的身份验证可以使用Windows内置的本地用户账户数据库(我想它被称为SAM)。
我知道如果设置了Active Directory,您可以使用PHP LDAP模块连接并在脚本中进行身份验证,但是没有AD就没有LDAP。对于独立机器,有什么等效的方法吗?
我正在使用PHP、Apache和Windows。由于我没有设置域名,因此我希望我的网站基于表单的身份验证可以使用Windows内置的本地用户账户数据库(我想它被称为SAM)。
我知道如果设置了Active Directory,您可以使用PHP LDAP模块连接并在脚本中进行身份验证,但是没有AD就没有LDAP。对于独立机器,有什么等效的方法吗?
我也没有找到简单的解决方案。有一些例子使用CreateObject和WinNT ADSI提供程序。但最终它们都会遇到Active Directory Service Interfaces WinNT provider的用户身份验证问题。我不确定,但我猜WSH /网络连接方法也有同样的问题。
根据如何在Microsoft操作系统上验证用户凭据,您应该使用LogonUser或SSPI。
它还说
在Windows XP上,进程不再需要具有SE_TCB_NAME特权才能调用LogonUser。因此,在Windows XP上验证用户凭据的最简单方法是调用LogonUser API。因此,如果我确定不需要Win9x/2000支持,我将编写一个扩展程序,将LogonUser暴露给php。在Microsoft Windows Server 2003中,LogonUser Win32 API不需要TCB特权,但出于向下兼容性的考虑,这仍然是最佳途径。
编辑:
我也尝试使用System.Security.Principal.WindowsIdentity和php的com/.net扩展。但是dotnet构造函数似乎不允许将参数传递给对象构造函数,而从GetType()获取程序集(以及CreateInstance())的“实验”失败了,出现了“未知zval”错误。
构建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>
好问题!
我认真思考了一下,但是我找不到一个好的解决方案。我只能想到一个可怕的 hack 方法,它可能会奏效。看到没有人在近一天内对这个问题发表答案,我觉得一个糟糕但可行的答案应该可以。
系统运行时,SAM 文件是不可访问的。有一些 DLL 注入技巧,也许你可以让它们工作,但最终你只会得到密码哈希值,而且你必须对用户提供的密码进行哈希以与之匹配。
你真正想要的是尝试使用 SAM 文件对用户进行身份验证。我认为你可以通过以下方式实现:
我知道它不太好看,但应该能用。
我感觉很不舒服 :|
编辑:调用外部wsh脚本的原因是PHP不允许使用UNC路径(据我所记)。