如何使用Zend OpenID实现基于直接身份的OpenID认证?

16
我正在使用Zend框架和来自http://code.google.com/p/openid-selector/的openid选择器,但是我发现我不能使用像Google和Yahoo这样使用基于直接身份验证登录系统的网站。因为它们只是将您重定向到一个url,而不是输入他们自己的唯一url进行身份验证。
我已经尝试了许多选项和技巧,但没有一个似乎有效。顺便问一下,在Stack Overflow上如何实现此功能?我真的需要大家的帮助。
编辑
问题在于从我注意到的情况来看,Zend OpenID类不支持OpenID 2.0。典型的OpenID提供商会给您一个唯一的URL,例如your-name.openid-providor.com或openid-providor.com/your-name,然后Zend OpenId类会解析该URL并将您重定向到提供程序网站,在那里进行身份验证后再将您重定向回来。
对于Yahoo和Google,你不需要输入一个唯一的URL,而是被重定向到提供者的登录网站,在登录和验证后再将您重定向回来。所以基本上zend_openID对象在解析提供者时,无法从常规URL中识别提供者。比如当你点击Google链接时,它会重定向你到https://www.google.com/accounts/o8/id
这更多是Zend OpenID对象的问题,并且在Zend相关论坛上没有任何帮助。因此,我想知道是否有人已经破解或者有一个可以修改该类以实现此目的的方法。对不起,如果我缺少一些东西,但是我对这个和OpenID编程还很陌生,刚刚开始入门。

感谢您的跟进 - 我之前曾经查看过 RPX,他们有一个 PHP 类,但我没有试用它,目前我只想让类似 Stackoverflow 的代码选择器能够与 Yahoo 和 Google 认证一起使用。肯定有一些方法可以调整 Zend OpenID 类使用的解析方式,因为它运行了一系列正则表达式检查来进行发现。

7个回答

9

虽然有点晚,但我通过在互联网上找到的一些技巧,成功地解决了这个问题。

首先是雅虎。为了让雅虎正常工作,我只需要将JavaScript中使用的yahoo.com更改为me.yahoo.com,并且它可以与我正在使用的Zend Framework版本完美配合。不幸的是,Google仍然无法正常工作,因此需要进行一些修改。

所有这些更改都在Zend/OpenId/Consumer.php文件中进行。

首先,在_discovery方法中,在大约740行左右开始的一系列preg_match检查中添加以下内容。

} else if (preg_match('/<URI>([^<]+)<\/URI>/i', $response, $r)) {
    $version = 2.0;
    $server = $r[1];

我在else {}块中的return false;语句之前添加了这个代码。

其次,在_checkId方法中,您需要添加3个新块(我还没有深入挖掘知道是什么原因导致调用这三种情况,因此我涵盖了所有内容以确保安全)。

在$version <= 2.0块内,您将找到if / else if / else块。 在第一个if语句($this->_session !== null)中,将其添加到末尾:

if ($server == 'https://www.google.com/accounts/o8/ud') {
    $this->_session->identity = 'http://specs.openid.net/auth/2.0/identifier_select';
    $this->_session->claimed_id = 'http://specs.openid.net/auth/2.0/identifier_select';
}

在 else if (defined('SID') 块的末尾添加以下内容:
if ($server == 'https://www.google.com/accounts/o8/ud') {
    $_SESSION['zend_openid']['identity'] = 'http://specs.openid.net/auth/2.0/identifier_select';
    $_SESSION['zend_openid']['claimed_id'] = 'http://specs.openid.net/auth/2.0/identifier_select';
}

在if/else if/else块之后(所以完全在外面,但仍然在$version <= 2.0块内),添加以下内容:

if ($server == 'https://www.google.com/accounts/o8/ud') {
    $params['openid.identity'] = 'http://specs.openid.net/auth/2.0/identifier_select';
    $params['openid.claimed_id'] = 'http://specs.openid.net/auth/2.0/identifier_select';
}

Zend框架问题跟踪器中的错误链接


(说明:此链接指向Zend框架问题跟踪器中的错误页面)

有点晚了,但还是谢谢你的提示,我会收藏这个链接,以备将来需要。目前,我已经仔细地调整并将JanRain库集成到我的代码中。感谢提供信息 ;) - Ali
这三个块的调用取决于会话是否已经启动以及相关的Zend会话类是否已经启动。第一个块是真实的,如果Zend_Session已被用来启动会话并存储在消费者对象的_session变量中。第二个块是真实的,如果会话已经通过session_start()或session.auto_start启动。最后一个块使用Zend_Session_Namespace开始一个新的会话。 - bearvrrr

3

我需要使用谷歌的OpenID功能,我尝试了Steven的代码,但无法直接使用。我做了一些修改。

_discovery更改的方法仍然相同:

在Zend/OpenId/Consumer.php文件的第765行添加:

} else if (preg_match('/<URI>([^<]+)<\/URI>/i', $response, $r)) {
    $version = 2.0;
    $server = $r[1];

其余部分有所不同:

在进行上述更改后,Zend/OpenId/Consumer.php文件的第859行添加如下内容:

if (stristr($server, 'https://www.google.com/') !== false) {
    $id = 'http://specs.openid.net/auth/2.0/identifier_select';
    $claimedId = 'http://specs.openid.net/auth/2.0/identifier_select';
}

这是之前的内容:

$params['openid.identity'] = $id;

$params['openid.claimed_id'] = $claimedId;

一旦获得授权,要使其返回ID:

Zend/Auth/Adapter/OpenId.php,第278行:

if(isset($_REQUEST['openid_identity']))
{
    $this->_id = $_REQUEST['openid_identity'];
    $id = $this->_id;
}

这是之前的内容:

return new Zend_Auth_Result(
    Zend_Auth_Result::SUCCESS,
    $id,
    array("Authentication successful"));

请注意,我没有彻底测试过这段代码。以下代码更加不稳定。
我花费了更多时间,并通过以下更改使其与我的Google Apps域名一起工作:
Zend/OpenId/Consumer.php,第734行。
        $discovery_url = $id;
        if(strpos($discovery_url, '/', strpos($discovery_url, '//')+2) !== false) {
            $discovery_url = substr($discovery_url, 0, strpos($discovery_url, '/', strpos($discovery_url, '//')+2));
        }
        $discovery_url .= '/.well-known/host-meta';
        $response = $this->_httpRequest($discovery_url, 'GET', array(), $status);
        if ($status === 200 && is_string($response)) {
            if (preg_match('/Link: <([^><]+)>/i', $response, $r)) {
                $id = $r[1];
            }
        }

这是紧接着的内容:

/* TODO: OpenID 2.0 (7.3) XRI and Yadis discovery */

我相信这是我需要做出的唯一更改。我很确定上述内容应该包括一些安全检查,但我还没有深入研究过它们会是什么。


谢谢你的建议 - 我刚刚放弃使用Zend类库,改用JanRains OpenID库。我想,如果我必须修改现有代码,那么在更健壮的代码模型上创建自己的包装类会更有意义。 - Ali

2
经过仔细考虑,我决定放弃使用 zend_openid 类[对不起,Zend],转而使用 JanRain 的 OpenID 库。虽然花费了几个小时将其与我的项目整合并运行,但至少它像微风一样顺畅地运行。为了让它正常工作,我不得不进行大量的修改和代码溢出。
由于该库自行进行认证,我无法使用任何 Zend 适配器与 Zend-Auth 配合使用以使新代码库融入其中。因此,我进行了一些修改,并创建了一个通用适配器,只需返回填充了 Zend-Result 的 Auth 对象即可进行身份验证,这样我就可以使用自己的库进行身份验证,并将结果存储在 Auth 对象中,从而欺骗 Zend-Auth 对象,而不必再次重写代码。
该库可以在以下网址找到:http://openidenabled.com/php-openid/ 感谢大家提供的所有帮助。

1

我也遇到了类似的问题。我计划在Zend Framework中使用RPX now。也许我会写一个适配器。只是提醒您一下。

信息:'RPS now' 提供了一个全合一的界面和用户注册界面,包括

  • Facebook
  • 谷歌
  • 雅虎
  • MySpaceID
  • Windows LiveID
  • OpenID
  • AOL

1

我非常确定Yahoo仅支持OpenID 2.0。如果你想支持Yahoo用户,你需要升级到一个支持2.0的库。这不仅仅是一些解析调整的问题。


0
你看过手册了吗 -- Zend_OpenId_Consumer basics?在那个页面上看看 38.2.2,然后告诉我这是否有帮助,因为应该会有用。
具体来说,我不知道 Google 是否提供 OpenID。我知道 Yahoo 可以使用,因为我之前试过。

实际上,我正在手册中使用这段代码。 但是它根本无法与Google和Yahoo一起使用。 我已经尝试了一些在线技巧,但它们都不起作用:( 顺便问一下,Stack Overflow是如何完成这个的? - Ali
@Ali Stackoverflow是建立在asp.net上的(我想)。无论如何,我建议您提供更多信息,例如您的代码、错误消息——然后我可以尝试帮助您。或者您可以在fw-general@邮件列表上发布。 - Till
谷歌不提供OpenID,谷歌有自己的GoogleID,可以与OpenID关联。 - markus

0

感谢提供的信息。我一开始使用了JanRain的库,但是在使用Simple Registration时遇到了问题:我没有成功获取到任何数据。而且关于使用Attribute Exchange也没有任何文档可供参考。:(

所以,我发现并尝试了Zend/OpenId,但和你一样遇到了同样的问题:没有Yahoo!、Google和其他支持。阅读这篇文章后,似乎我只能回到JanRain;RPX对我来说不是一个选项,因为它是第三方服务。


使用JanRain可能有些麻烦,但它非常强大。您需要创建一个完全通用的身份验证适配器,不进行任何身份验证,因为所有身份验证都将由JanRain完成。您创建的通用适配器仅会在身份验证成功后从JanRain返回基本信息,例如OpenID代码和您选择填充适配器的任何其他信息... - Ali
JanRain很痛苦。知道Zend也很痛苦,真是令人难过:( - jayarjo

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