【问题标题】:Why is $auth->loggedIn never true in my use of CGI::Session::Auth::DBI?为什么在我使用 CGI::Session::Auth::DBI 时 $auth->loggedIn 永远不会为真?
【发布时间】:2010-01-23 02:11:50
【问题描述】:

使用CGI::Session::Auth::DBICGI::Session::Auth 页面中的示例,我尝试实现_login 函数,但没有成功。我使用的是 Windows 7 和 Apache 2。

#!/usr/bin/perl -w
use strict;

use CGI::Carp qw(fatalsToBrowser);

use CGI;
use CGI::Session;
use CGI::Session::Auth::DBI;

my $cgi = new CGI;

# using '.' directory for testing
my $session = new CGI::Session(undef, $cgi, {Directory=>'.'});
my $auth = new CGI::Session::Auth::DBI({
    CGI => $cgi,
    Session => $session,
    DSN => 'dbi:mysql:dbname=foobar:host=localhost',
    DBUser => 'foo',
    DBPasswd => 'bar',
    UserTable => 'cgi_auth_user' # auth_user already in use
});

print "Content-type: text/html\n\n";

if ($auth->_login("admin", "admin")) {
    print "<p>login ok</p>";
} else {
    print "<p>login fail</p>";
}

if ($auth->loggedIn) {
    print "<p>logged in; go to <a href='index.pl'>index</a></p>";
} else {
    print "<p>not logged in</p>";
}

由此得到的渲染输出是:

login ok
not logged in

如果我将传递给_login 的值更改为“foo”、“bar”(无效的用户名/密码),那么我会得到这个渲染结果:

login fail
not logged in

我正在使用“。”只是为了测试,因为我知道这是我可以写的目录。每次我运行代码时,都会创建一个cgisess_ 文件(例如cgisess_9fb493cc9155ee9dd2b18fddc38139d8),但无论我是否使用正确的用户名,都会创建这个文件。没有返回任何错误,但 $auth-&gt;loggedIn 始终为 false。

文档说_login 是虚拟的,听起来 DBI 模块会覆盖它,但我不确定。

我做错了什么?

更新 1:

在调用$auth-&gt;loggedIn 之前,我也尝试过使用$auth-&gt;authenticate(),但这没有效果。成功登录后,我还尝试在另一个上使用$auth-&gt;authenticate()$auth-&gt;loggedIn,但我得到了相同的结果。不管我做什么,$auth-&gt;loggedI 总是假的。

更新 2:

我也尝试将目录更改为“/”,它所做的只是在 / 而不是当前目录中创建 cgisess 文件。

更新 3:

我认为这可能是数据库记录的问题;我正在使用示例页面中的默认示例,但修改了管理员密码。这是一个 phpMyAdmin 导出:

CREATE TABLE IF NOT EXISTS `cgi_auth_user` (
  `userid` char(32) collate utf8_unicode_ci NOT NULL,
  `username` varchar(30) collate utf8_unicode_ci NOT NULL,
  `passwd` varchar(30) collate utf8_unicode_ci NOT NULL default '',
  PRIMARY KEY  (`userid`),
  UNIQUE KEY `username` (`username`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

INSERT INTO `cgi_auth_user` (`userid`, `username`, `passwd`) VALUES
('325684ec1b028eaf562dd484c5607a65', 'admin', 'admin'),
('ef19a80d627b5c48728d388c11900f3f', 'guest', 'guest');

再一次,如果_login 使用有效的用户名和密码返回true,那么我会假设用户ID 是有效的......不是吗?

更新 4:

我也在我们的 Linux 生产服务器上对此进行了测试,我遇到了完全相同的问题。

【问题讨论】:

  • 避免使用间接对象表示法(即new CGI)。使用方法调用语法(即CGI-&gt;new)。见perldoc.perl.org/perlobj.html#Indirect-Object-Syntaxperlbuzz.com/mechanix/2008/02/…
  • 我只是查看了代码,并且 ::DBI 模块确实覆盖了_login。至于为什么您的代码不起作用:数据库设置了吗?你看过错误日志吗?可以打开调试吗?
  • 是的,数据库已设置并正在运行;为了证明这一点,我更改为错误的数据库用户名并收到数据库错误。我应该使用perl 开关打开调试信息吗?我查看了--help,但我不了解调试部分;也许这应该是一个新问题?
  • $auth->Log=1(来自阅读源代码)
  • 您可以尝试使用 Perl 调试器运行它——我个人觉得它有点令人困惑。我想如果您可以从命令行运行 CGI 脚本,这是一个可行的选择。 Auth 模块确实有内置的调试语句 - 查看源代码。正如 ergosys 指出的那样,有一个 Log 标志(到 new)。我认为您可能还需要提供一个初始化的 Log4Perl 对象...抱歉,不是这些模块的专家(从未使用过它们)只是想提供帮助;-)

标签: perl authentication cgi


【解决方案1】:

尝试将$session-&gt;header() 的结果作为您输出的第一件事。这应该设置您的 cookie 并加载现有会话,而不是每次都创建一个新会话。

另外,_login() 只对数据库进行身份验证,而不会修改$auth 对象。使用authenticate(),您需要使用$cgi 对象的param() 函数定义用户名和密码。您需要设置字段log_usernamelog_password 才能使authenticate() 函数起作用。

#!/usr/bin/perl -w
use strict;

use CGI::Carp qw(fatalsToBrowser);

use CGI;
use CGI::Session;
use CGI::Session::Auth::DBI;

my $cgi = CGI->new;
my $session = new CGI::Session(undef, $cgi, {Directory=>'/tmp'});

my $auth = new CGI::Session::Auth::DBI({
    CGI => $cgi,
    Session => $session,
    DSN => 'dbi:mysql:dbname=foobar:host=localhost',
    DBUser => 'foo',
    DBPasswd => 'bar',
    UserTable => 'cgi_auth_user'
});

print $session->header();

$cgi->param('log_username', 'admin');
$cgi->param('log_password', 'admin');

$auth->authenticate();

if ($auth->loggedIn) {
    print "<p>logged in; go to <a href='index.pl'>index</a></p>";
} else {
    print "<p>not logged in</p>";
}

我还没有测试过,但这应该可以工作。

【讨论】:

  • 完美;我想知道这是否是一种黑客方式?示例代码没有提到我们需要设置$cgi-&gt;param——我假设它会使用 POST 值,但我尝试了这个但没有运气。无论如何,你的答案有效,所以谢谢!
  • 啊!实际上我只是用 POST 重新尝试,结果你需要在字段名称之前使用 log_:print '&lt;form method="post"&gt;&lt;input type="text" name="log_username" /&gt;&lt;input type="password" name="log_password" /&gt;&lt;input type="submit" /&gt;&lt;/form&gt;';
  • 我相信你也可以使用 GET,但这不会太安全。 ;)
【解决方案2】:

文档很清楚你必须重写 _login() 方法,除非客人/客人适合你。另外你没有调用authenticate(),它实际上调用了_login(),你不应该这样做。

_login()

这个虚方法执行 通过比较实际登录尝试 访问者发送的登录表单数据 一些本地用户数据库。 _login 基类的方法 CGI::Session::Auth 只知道用户 'guest' 密码为 'guest'。

要访问真实的用户数据库,您 必须使用修改的子类 _login 方法适当。看 Auth/ 子目录中的模块。

【讨论】:

  • “查看 Auth/ 子目录中的模块”。我认为部分有点误导;因为CGI::Session::Auth::DBI 在 Auth/ 子目录中(不是吗?)所以它让我假设这个模块覆盖了_login...
  • 顺便说一下,_login 在我使用有效的用户名和密码时返回 true,在我使用虚假凭据时返回 false。所以我相信我使用正确。我会更新我的答案。
  • 是的,在看了一点之后,我看到 _login() 被 DBI 覆盖了。 authenticate() 似乎默认使用“log_password”、“log_username”。
【解决方案3】:

查看源代码和文档,_login() 从未真正设置内部loggedin 标志。这仅在身份验证模块中执行。您还应该记住,普遍接受的 perl 实践是,以“_”开头的方法本质上应该被视为私有方法,(或者在 Java 术语中可能是受保护的)只供子类使用。所以你不应该直接使用 _login。

LoginVarPrefix:默认情况下,CGI::Session::Auth 期望访问者的用户名和密码以表单变量“log_username”和“log_password”的形式传递。为避免冲突,可以通过此参数更改前缀“log_”。

我相信这会奏效

$session->param('log_username', 'admin');
$session->param('log_password', 'admin');

$auth->authenticate(); # no return value to check

print "Content-type: text/html\n\n";

if ($auth->loggedIn) {
    print "<p>logged in; go to <a href='index.pl'>index</a></p>";
} else {
    print "<p>not logged in</p>";
}

【讨论】:

  • 谢谢,我明天试试。
  • 嗯,仍然返回“未登录”——我复制并粘贴了您的代码。
  • 啊哈!差不多,看看沃尔夫的回答。代码查看 $cgi 参数而不是 $session 参数。
【解决方案4】:

您可以通过将其放在 my $cgi = new CGI; 上方来打开日志记录。线

use Log::Log4perl qw(:easy);
# Set priority of root logger to DEBUG
Log::Log4perl->easy_init($DEBUG);

这将打开调试并让您看到更多正在发生的事情。

【讨论】:

  • 谢谢,我认为这会有所帮助。
  • 我必须安装 Log::Log4perl -- 页面加载正常,但如何查看调试输出?
猜你喜欢
  • 1970-01-01
  • 2016-10-12
  • 1970-01-01
  • 2013-07-22
  • 2018-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-05
相关资源
最近更新 更多