与所有主要提供商实施单点登录的最佳方式?

The*_*can 42 php openid authentication facebook single-sign-on

我已经对这个主题做了很多研究,并且自己实施了很多解决方案.

包括OpenID,Facebook Connect(使用旧的Rest API和新的Graph OAuth 2.0 API),使用twitter登录(据我所知,目前已经升级到完全合格的OpenID),依此类推......

但我仍然缺少的是完美的一体化解决方案.

在我的研究期间,我偶然发现了一些有趣的项目:

但我不想依赖外部提供商,我也想要一个免费的解决方案,所以我不受限制.

我还看到开发人员在遵循提供程序指令并为所有内容设置模型和数据库表之后,一个接一个地实现一个服务.

当然这可以工作,但它是一大堆工作,总是需要开发和更改您的应用程序等.

我正在寻找的是一个抽象层,它将所有服务都带到一个可以集成到我网站的标准中.一旦出现新服务,我只想添加一个处理该特定提供者抽象的模型,这样我就可以将它无缝地集成到我的应用程序中.

或者更好的是,找到一个我可以下载的现有解决方案.

理想情况下,这个抽象服务将独立于我的应用程序托管,因此它可以用于多个应用程序并独立升级.

上述3种解决方案中的最后一种看起来很有希望.一切都只是移植到合成的OpenID,网站jut必须实现OpenID.

过了一会儿,我找到了Django socialauth,一个基于python的Django Webframework身份验证系统.但它看起来像上面描述的那样运行,我认为这是Stackoverflow使用的相同登录系统(或者至少是一些修改过的fork ...).

我下载了它,并试图设置它,看看它是否可以设置为一个独立的解决方案,但我没有运气,因为我也不是这样的python.

我很想要一个基于PHP的解决方案.

所以在这篇长篇文章之后,我的问题恰恰是:

  • 你如何实现SSO,比移植所有内容更好的想法并以OpenID为基础?
  • 有什么优点和缺点?
  • 你知道任何现有的解决方案吗?首选开源.

我希望这个问题不是太主观,提前谢谢.

更新:我的结论是构建一个代理/包装器或者你可以称之为Facebook的东西,将它移植到一个OpenID,因此它成为一个OpenID端点/提供者将是最好的选择.这就是我所做的.

请参阅下面的答案.

我添加了赏金以获得反馈/讨论.Maby我的方法并不像我现在认为的那样好!

The*_*can 13

作为这个答案的原作者,我想指出我认为它是 过时的.由于大多数提供商决定专门实施Oauth而不是Openid.较新的Openid服务也可能使用基于oauth的openid connect.有很好的库,例如:https://github.com/hybridauth/hybridauth

在讨论了现有的答案后,我总结了一下:

几乎每个主要提供商都是一个开放的提供商/端点,包括Google,Yahoo,Aol.

其中一些要求用户指定用于构造openid端点的用户名.其中一些(上面提到的那些)确实有发现网址,其中自动返回用户ID,以便用户只需点击即可.(如果有人能解释技术背景,我会很高兴)

然而,屁股的唯一痛苦是Facebook,因为他们有Facebook连接,他们使用改编版本的OAuth进行身份验证.

现在,我为我的项目所做的是设置一个openid提供程序,使用我的facebook应用程序的凭据对用户进行身份验证 - 这样用户就可以连接到我的应用程序 - 并返回一个如下所示的用户ID:

http://my-facebook-openid-proxy-subdomain.mydomain.com/?id=facebook-user-id
Run Code Online (Sandbox Code Playgroud)

我还将其配置为获取电子邮件地址和名称,并将其作为AX属性返回.

所以我的网站只需要实现opend id,我很好:)

我建立在你可以在这里找到的课程:http://gitorious.org/lightopenid

在我的index.php文件中,我只是这样称呼它:

<?php
require 'LightOpenIDProvider.php';
require 'FacebookProvider.php';
$op = new FacebookProvider;
$op->appid = 148906418456860; // your facebook app id
$op->secret = 'mysecret'; // your facebook app secret
$op->baseurl = 'http://fbopenid.2xfun.com'; // needs to be allowed by facebook
$op->server();
?>
Run Code Online (Sandbox Code Playgroud)

以及FacebookProvider.php的源代码如下:

<?php
class FacebookProvider extends LightOpenIDProvider
{
    public $appid = "";
    public $appsecret = "";
    public $baseurl = "";

    // i have really no idea what this is for. just copied it from the example.
    public $select_id = true;

    function __construct() {

        $this->baseurl = rtrim($this->baseurl,'/'); // no trailing slash as it will be concatenated with
                                                    // request uri wich has leading slash

        parent::__construct();

        # If we use select_id, we must disable it for identity pages,
        # so that an RP can discover it and get proper data (i.e. without select_id)
        if(isset($_GET['id'])) {
            // i have really no idea what happens here. works with or without! just copied it from the example.
            $this->select_id = false;
        }
    }

    function setup($identity, $realm, $assoc_handle, $attributes)
    {
        // here we should check the requested attributes and adjust the scope param accordingly
        // for now i just hardcoded email
        $attributes = base64_encode(serialize($attributes));    

        $url = "https://graph.facebook.com/oauth/authorize?client_id=".$this->appid."&redirect_uri=";

        $redirecturl = urlencode($this->baseurl.$_SERVER['REQUEST_URI'].'&attributes='.$attributes);
        $url .= $redirecturl;
        $url .= "&display=popup";
        $url .= "&scope=email";
        header("Location: $url");
        exit();        

    }

    function checkid($realm, &$attributes)
    {
        // try authenticating
        $code = isset($_GET["code"]) ? $_GET["code"] : false;
        if(!$code) {
            // user has not authenticated yet, lets return false so setup redirects him to facebook
            return false;
        }

        // we have the code parameter set so it looks like the user authenticated
        $url = "https://graph.facebook.com/oauth/access_token?client_id=148906418456860&redirect_uri=";

        $redirecturl = ($this->baseurl.$_SERVER['REQUEST_URI']);
        $redirecturl = strstr($redirecturl, '&code', true);
        $redirecturl = urlencode($redirecturl);     
        $url .= $redirecturl;
        $url .= "&client_secret=".$this->secret;
        $url .= "&code=".$code;
        $data = $this->get_data($url);

        parse_str($data,$data);

        $token = $data['access_token'];

        $data = $this->get_data('https://graph.facebook.com/me?access_token='.urlencode($token));
        $data = json_decode($data);

        $id = $data->id;
        $email = $data->email;
        $attribute_map = array(
            'namePerson/friendly' => 'name', // we should parse the facebook link to get the nickname
            'contact/email' => 'email',
        );

        if($id > 0) {

            $requested_attributes = unserialize(base64_decode($_GET["attributes"]));

            // lets be nice and return everything we can
            $requested_attributes = array_merge($requested_attributes['required'],$requested_attributes['optional']);
            $attributes = array();
            foreach($requested_attributes as $requsted_attribute) {
                if(!isset($data->{$attribute_map[$requsted_attribute]})) {
                    continue; // unknown attribute
                }
                $attributes[$requsted_attribute] = $data->{$attribute_map[$requsted_attribute]};    
            }

            // yeah authenticated!
            return $this->serverLocation . '?id=' . $id ;
        }
        die('login failed'); // die so we dont retry bouncing back to facebook
        return false;
    }
    function get_data($url) { 
      $ch = curl_init();
      $timeout = 5;
      curl_setopt($ch,CURLOPT_URL,$url);
      curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
      curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,$timeout);
      $data = curl_exec($ch);
      curl_close($ch);
      return $data;
    }    

}
Run Code Online (Sandbox Code Playgroud)

它只是第一个工作版本(快速和肮脏)一些动态的东西是硬编码我的需求.它应该显示如何以及它可以完成.我很高兴,如果有人拿起并改进它或重新写它或其他:)

我认为这个问题得到了回答

但我加上一笔赏金只是为了讨论.我想知道你对我的解决方案的看法.

我会将赏金奖励给旁边的最佳答案/评论.


xaa*_*aav 5

OpenID将是您应用此选项的最佳选择.它受到许多提供商的支持:

  • 谷歌
  • 雅虎
  • 者myOpenID
  • AOL

唯一的问题是Twitter还没有实现OpenID.这可能是因为他们是一家以公司为基础的公司,所以他们想要自己的"解决方案".

要解决该解决方案,您可以编写一个包装类来提供与OpenID的兼容性,但即使您的用户没有Twitter帐户,他们也可能拥有Facebook,Google或Yahoo帐户.

Facebook支持oauth,因此您必须将oauth移植到OpenID

可以在此处找到一些OpenID的PHP库.

现在,有人提出一些关于facebook是oauth提供者的问题.

他们的oauth URL是"https://graph.facebook.com/oauth/authorize"

如果你仍然不相信我,那么你可以看看这个 javascript文件,我在那里得到了这个URL.如果你不相信javascript文件,那么请注意它是由stackexchange托管的,这是该网站的提供者.现在你必须相信这一点.

  • @geoff:OpenID!= OAuth.例如,尝试使用您发布的facebook"openid"网址验证stackoverflow.com. (2认同)