web-dev-qa-db-ja.com

すべての主要プロバイダーでシングルサインオンを実装する最良の方法は?

私はすでにこのトピックについて多くの研究を行い、多くの解決策を自分で実装しました。

OpenID、Facebook Connect(古いRest APIと新しいGraph OAuth 2.0 APIを使用)を含む)、Twitterでサインイン(これは、私が知る限り、完全修飾OpenIDにアップグレードされています) 、 等々...

しかし、私がまだ足りないのは、1つのソリューションで完璧なものです。

調査中、私はいくつかの興味深いプロジェクトに出くわしました:

しかし、私は外部プロバイダーに依存したくないし、無料のソリューションも欲しいので、実装に制限はありません。

また、プロバイダーの指示に忠実に従い、すべてのモデルとデータベーステーブルをセットアップする開発者が次々とサービスを実装するのを見てきました。

もちろんこれはうまくいきますが、それは仕事のたわごとであり、常にアプリケーションの開発や変更などが必要です。

私が探しているのは、抽象化レイヤーです。これにより、すべてのサービスを、私のWebサイトに統合できる1つの標準に変換できます。新しいサービスが表示されたら、その特定のプロバイダーの抽象化を扱うモデルを1つだけ追加して、アプリケーションにシームレスに統合できるようにします。

または、私がダウンロードできない既存のソリューションを見つけます。

理想的には、この抽象化サービスはアプリケーションから独立してホストされるため、複数のアプリケーションで使用したり、独立してアップグレードしたりできます。

上記の3つのソリューションの最後は、コンセプトから有望に見えます。すべてが合成OpenIDに移植されるだけで、ウェブサイトのjutはOpenIDを実装する必要があります。

しばらくして、私は Django socialauth を見つけましたpython Django Webframeworkの認証システムです。しかし、上記で説明したとおり、これはStackoverflowが使用するのと同じログインシステム(または少なくともいくつかの変更されたフォーク...)だと思います。

私はそれをダウンロードしてセットアップし、スタンドアロンソリューションとしてセットアップできるかどうかを確認しようとしましたが、pythonもそうではないので、運がありませんでした。

PHPベースのソリューションが大好きです。

したがって、この長いテキストの後、私の質問は正確に次のとおりです。

  • すべてを移植してOpenIDをベースにするよりも良い方法で、SSOをどのように実装しますか?
  • その長所と短所は何ですか?
  • 既存のソリューションを知っていますか?できればオープンソース。

この質問が主観的になりすぎないことを願っています。

更新:私は、プロキシ/ラッパーを構築するか、FacebookでそれをOpenIDに移植してOpenIDエンドポイント/プロバイダーになるように構築するのが最良のオプションであると結論付けました。だから私がやったことと同じです。

以下の私の答えを見てください。

私はそれについてフィードバック/議論を得るために賞金を追加しました。私のアプローチは、私が現在思っているほど良くはありません!

42
The Surrican

この回答の原作者として、私はそれを[〜#〜]時代遅れ[〜#〜]と見なしていることに注意したいと思います。ほとんどのプロバイダーは、Openidの代わりにOauthを独占的に実装することを決定しました。新しいOpenidサービスも、oauthに基づくopenid connectを使用する可能性があります。たとえば、次のような優れたライブラリがあります。 https ://github.com/hybridauth/hybridauth

既存の回答についての議論の後、私は要約します:

ほぼすべての主要プロバイダーは、Google、Yahoo、AolなどのOpenIDプロバイダー/エンドポイントです。

それらのいくつかは、openidエンドポイントを構築するためにユーザー名を指定するようユーザーに要求します。それらの一部(上記のもの)には、ユーザーがクリックするだけで済むようにユーザーIDが自動的に返されるディスカバリーURLがあります。 (誰かが技術的背景を説明できたらうれしいです)

ただし、認証にOAuth)の適応バージョンを使用するFacebook接続があるため、お尻の唯一の痛みはFacebookです。

次に、私のプロジェクトで行ったのは、Facebookアプリケーションの資格情報でユーザーを認証するopenidプロバイダーをセットアップすることです。これにより、ユーザーはアプリケーションに接続し、次のようなユーザーIDを返します。

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

また、メールアドレスと名前を取得して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();
?>

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

}

その最初の作業バージョン(クイックでダーティ)だけです。動的なものは、私のニーズにハードコードされています。それは、どのように、そしてそれができるのかを示すべきです。誰かがそれを拾って改善したり、それを書き直したりしても何でもいいです:)

よく私はこの質問が答えられたと考えます

しかし、私は議論を得るためだけに賞金を追加します。あなたが私の解決策についてどう思うか知りたいのですが。

この賞の横にあるベストアンサー/コメントに賞金を授与します。

13
The Surrican

OpenIDは、このアプリケーションの最善の策になるでしょう。それは多くのプロバイダーによってサポートされています:

  • グーグル
  • ヤフー
  • MyOpenID
  • AOL

唯一の問題は Twitter がまだOpenIDを実装していないことです。これはおそらく、彼らが所有権に基づく会社であるという事実によるため、彼らは「独自の」ソリューションを求めていました。

この解決策を解決するには、OpenIDとの互換性を提供するラッパークラスを記述しますが、ユーザーがTwitterアカウントを持っていなくても、Facebook、Google、またはYahooアカウントを持っている可能性があります。

Facebookはoauthをサポートしているため、oauthをOpenIDに移植する必要があります。

いくつかのPHP OpenIDのライブラリが見つかります ここ

現在、Facebookがoauthプロバイダーであることについて、いくつかの質問が出されています。

彼らのoauth URLは "https://graph.facebook.com/oauth/authorize"です

それでも私を信じられない場合は、 this javascriptファイルを見てください。ここで、そのURLを取得しています。そのJavaScriptファイルを信じられない場合は、このサイトのプロバイダーであるstackexchangeによってホストされていることに注意してください。今あなたはそれを信じなければなりません。

5
xaav

2年早送りし、「OpenIDが答えです」という答えは、多くの大手プロバイダーによって道端に落ちているようです。主要なサードパーティ統合サイトのほとんどは、OAuth(通常はOAuth2)のフレーバーに移行しているようです。また、OpenID/OAuthを使用しないことを気にしない場合は、 PHPで記述された完全なSSOソリューション(免責事項および完全な開示:この製品は、CubicleSoftバナーの下で自分で開発および保守しています):

シングルサインオンサーバー/クライアント

この質問が最初に尋ねられたとき、それは存在しませんでした。リベラルライセンス(MITまたはLGPL)があり、抽象化レイヤーであるという要件を満たしています。このプロジェクトは企業のサインインに重点を置く傾向がありますが、ソーシャルメディアのサインインもいくつかあります(GoogleとFacebook)。

HybridAuth も確認することをお勧めします。これは、ソーシャルメディアのサインインにのみ焦点を当てていますが、サーバーにスローして実行できる事前構築済みのソリューションよりもライブラリのようなものです。そのため、設定にはもう少し作業が必要です。それは本当にあなたが何をしているかに依存します。

OpenIDソリューションに満足している場合はすばらしいですが、今日は2年前よりも多くのオプションがあり、人々はまだこのスレッドを見つけています。

2
CubicleSoft