实现单点登录与所有主要供应商的最佳方式? [英] Best way to implement Single-Sign-On with all major providers?

查看:185
本文介绍了实现单点登录与所有主要供应商的最佳方式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经做了很多研究这个问题,并已实施了很多解决方案自己。

I already did a lot of research on this topic and have implemented a lot of solutions myself.

包括OpenID的,Facebook连接(使用旧的REST API和新的图形中的Oauth 2.0 API),登录与Twitter(至极已被作为现在据我所知升级到完全合格的OpenID),等等..

Including OpenID, Facebook Connect (using the old Rest api and the new Graph Oauth 2.0 Api), Sign in with twitter (wich has been upgraded to fully qualified Openid by now as far as I know), and so on...

但我仍然缺少的是完美于一身的解决方案。

But what I'm still missing is the perfect all in one solution.

在我的研究,我stumpled一些有趣的项目:

During my research I stumpled about some interesting projects:

  • Janrain (formerly RPX) - a commercial solution
  • Gigya - a free but externally hosted solution with javascript and rest apis
  • Anyopenid - a free solution for clients, commercial for websites

但我不希望依赖于外部供应商,我想免费的解决方案一样,所以我不实施限制。

But I don't want to rely on an external provider and I would like a free solution as well, so I am not limited in implementation.

我也看到了开发者实现一个服务陆续dutyfully继提供商instructinos和建立模型和数据库表的一切。

I have also seen developers implementing one service after another dutyfully following the providers instructinos and setting up models and database tables for everything.

当然,这会工作,但它是一个工作shitload,总是需要研究与开发,并在应用程序中的变化等。

Of course this will work but it is a shitload of work and always needs developement and changes in your application etc.

我所寻找的是一个抽象层这需要所有的服务都来一个标准,可以集成在我的网站。一旦一个新的服务似乎我只是想添加一个模型,与特定供应商的抽象论述,所以我可以无缝地集成到我的应用程序。

What I am looking for is an abstraction layer that takes all the services out there to one standard that can be integrated in my website. Once a new service appears I only want to add one model that deals with the abstraction of that specific provider so I can seamlessly integrate it into my application.

或者更好的,发现我可以只dowonload一个已经存在的解决方案。

Or better, find an already existing solution that I can just dowonload.

理想情况下这种抽象服务将被独立地从我的应用程序托管因此它可用于多种应用和独立升级。

Ideally this abstraction service would be hosted independently from my application so it can be used for several applications and be upgraded independently.

最后3解决方案上面看起来与概念大有可为。
一切都只是移植到合成的OpenID,网站突出部分必须实现的OpenID。

The last of the 3 solutions above looks promising from the concept. Everything is just ported to an synthetic openid, and the website jut has to implement openid.

有一段时间我发现<一后href=\"http://uswaretech.com/blog/2009/08/django-socialauth-login-via-twitter-facebook-openid-yahoo-google/\">Django socialauth ,对于Django的Webframework一个基于Python的认证系统。但看上去,上述像它的运作,我认为这是同一个登录系统使用计算器(或至少一些改良叉...)。

After a while i found Django socialauth, a python based authentication system for the Django Webframework. But it looks like it operates as described above and i think this is the same login system that Stackoverflow uses (or at least some modified fork...).

我下载了它,并试图对其进行设置,并查看它是否可以设置为一个独立的解决方案,但我没有运气,因为我不是那么到Python两种。

I downloaded it and tried to set it up and to see whether it could be set up as a standalone solution but I had no luck, as I am not so into python either.

我会爱一个基于PHP的解决方案。

I would love a PHP based solution.

因此​​,这长的文本后,我的问题precisely是:

So after this long text my question precisely is:


  • 你将如何实现SSO,比移植一切更好的主意,并有OpenID的作为依据呢?

  • 什么是该利弊?

  • 请您知道的任何现有的解决方案? preferrably开源。

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

I hope this question is not too subjective, thanks in advance.

更新:
我的结论是,建立一个代理/包装或者你可以称它为对于Facebook,将它移植到一个OpenID所以它beocmes一个OpenID端点/供应商将是最好的选择。
所以这正是我所做的。

Update: I concluded that building a proxy / wrapper or what you might call it for facebook, to port it to an openid so it beocmes an openid endpoint / provider would be the best option. So that exactly what i did.

请参阅我的回答如下。

我添加赏金来获得它的反馈/讨论。莫比我的做法是不太好,因为我现在认为这是!

I added the bounty to get feedback/discussion on it. Maby my approach is not so good as i currently think it is!

推荐答案

已经存在的答案我总结讨论后:

After the discussion of the already existing answer i sum up:

几乎每一个主要供应商是一个OpenID提供商/端点,包括谷歌,雅虎,AOL。

Almost every major provider is an openid provider / endpoint including Google, Yahoo, Aol.

他们中的一些requrie用户指定的用户名来构造OpenID端点。
其中一些(上面提到的那些)的确实有发现网址,其中,用户标识自动返回,以使用户只需要点击。 (我会很高兴,如果有人能解释技术背景)

Some of them requrie the user to specify the username to construct the openid endpoint. Some of them (the ones mentioned above) do have discovery urls, where the user id is automatically returned so that the user only has to click. (i would be glad if someone could explain the technical background)

然而,在屁股痛只有Facebook的是,因为他们有自己的Facebook连接,他们使用OAuth改编版进行身份验证。

However the only pain in the ass is Facebook, because they have their Facebook connect where they use an adapted version of OAuth for authentication.

现在我做什么我的项目是设置一个验证我的Facebook应用程序的凭据用户一个OpenID提供商 - 所以用户获取连接到我的应用程序 - 并返回一个用户ID,看起来像:

Now what I did for my project is to set up an openid provider that authenticates the user with the credentials of my facebook Application - so the user gets connected to my application - and returns a user id that looks like:

http://my-facebook-openid-proxy-subdomain.mydomain.com/?id=facebook-user-id

我也配置它作为AX属性来获取的电子邮件地址和名称,并返回它。

I also configured it to fetch email adress and name and return it as AX attributes.

所以,我的网站只是要实现运行结束的id和我很好:)

So my website just has to implement opend id and i am fine :)

我建立它在你可以在这里找到类: http://gitorious.org/lightopenid

I build it upon the classes you can find here: http://gitorious.org/lightopenid

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

In my index.php file i just call it like this:

<?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();
?>

和FacebookProvider.php源$ C ​​$ C如下:

and the source code of FacebookProvider.php follows:

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

}

它只是一个第一个工作版本(快速和肮脏的)
有些东西动是很难coded到我的需要。
它应该显示它是如何以及可以做到的。
我很高兴,如果有人拿起并提高它或重新编写,或任何:)

Its just a first working version (quick and dirty) Some dynamic stuff is hardcoded to my needs. It should show how and that it can be done. I am happy if someone picks up and improves it or re writes it or whatever :)

嗯,我考虑这个问题的回答

Well i consider this question answered

但我添加一个赏金只是为了得到讨论。我想知道你怎么想我的解决方案的。

but I add a bounty just to get discussion. I would like to know what you think of my solution.

我将颁发奖金这一个身边最好的答案/发表评论。

I will award the bounty to the best answer/comment beside this one.

这篇关于实现单点登录与所有主要供应商的最佳方式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆