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

我正在使用Zend框架和 http://code.google.com/p/openid-selector/ 的openid选择器 - 但是我发现我无法使用Google和Yahoo等网站登录,因为它们使用基于身份的直接登录系统,其中一个只是重定向到一个url,而不是输入他们自己的唯一URL进行身份验证。

我已经检查了许多选项和黑客,但它们似乎都不起作用。顺便说一句,我如何让它在这里工作 - 它是如何在堆栈溢出中实现的?我真的可以使用这里所有的帮助。


编辑

这里的问题是,从我注意到的是,Zend OpenID类不支持OpenID 2.0,问题是典型的开放ID提供器会给你一个唯一的url,例如 your-name.openid-providor.com 或 openid-providor.com/your-name 而Zend OpenId类只是解析该URL,然后将您重定向到提供者网站,在身份验证后您将被重定向回去。

在Yahoo和Google的情况下 - 您没有输入唯一的URL,而是被重定向到提供者登录站点,并且在登录和身份验证后您将被重定向回去 - 所以基本上,zend_openID对象在解析时会告诉提供者是谁,它无法从一般URL本身中分辨出来。就像当你点击谷歌链接时,它会将你重定向到 https://www.google.com/accounts/o8/id

这里更多的是zend openid对象的问题,并且在zend相关论坛上没有任何帮助 - 所以我想知道是否有人已经破解或可以对类进行更改以完成此操作。很抱歉,如果我错过了一些东西,但我有点新手,用开放的ID编程,刚刚开始弄湿我的脚。


感谢您的跟进 - 我确实检查了RPX一段时间,他们确实有一个php类,但我无法检查它,而且我真的只想现在让代码选择器用作stackoverflow,以使用Yahoo和Google身份验证。必须有某种方法来调整Zend OpenID类在运行一系列正则表达式检查以进行发现时使用的解析。


答案 1

游戏有点晚了,但我能够用我在互联网上发现的一些黑客来解决这个问题。

第一。雅虎。为了让雅虎工作,我所要做的就是将JavaScript更改为使用 me.yahoo.com 而不仅仅是 yahoo.com 并且它与我正在使用的Zend框架版本完美配合。不幸的是,谷歌仍然没有,所以一些黑客攻击是有序的。

所有这些变化都进入了Zend/OpenId/Consumer.php

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

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

我在 else {} 块中的语句之前添加了此内容。return false;

其次,在方法中,您需要添加3个新块(我还没有充分挖掘,不知道是什么原因导致这三种情况中的每一种都被调用,所以我涵盖了所有安全方块。_checkId

在 $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') 块中,将 this 添加到末尾:

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';
}

然后在 else 块之后(所以在 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框架问题跟踪器中的错误


答案 2

我需要使用Google的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 */

我相信这是我唯一需要做出的改变。我很确定出于安全原因,应该对上述内容进行一些检查,但我还没有深入研究它,看看它们会是什么。


推荐