8

私は基本的に、特定のユーザーの Facebook ID を保存して、Facebook 経由でより多くの資料を受け取ることができるようにしたいと考えています。理想的には、javascript も cookie も使用せず、サーバー側だけのソリューションが必要ですが、例がなく、指示だけがあったため、議論できるソリューションをまとめました。Web サイトの OAuth ダイアログにユーザーをリンクするだけで機能すると思われるコードを次に示します。

https://www.facebook.com/dialog/oauth?client_id=164355773607006&redirect_uri=http://www.kewlbusiness.com/oauth

次に、ユーザーデータを取得するために次のように処理します。

class OAuthHandler(webapp2.RequestHandler):
    def get(self):
      args = dict(
        code = self.request.get('code'),
        client_id = facebookconf.FACEBOOK_APP_ID,
        client_secret = facebookconf.FACEBOOK_APP_SECRET,
        redirect_uri = 'http://www.koolbusiness.com/oauth',
      )
      file = urllib.urlopen("https://graph.facebook.com/oauth/access_token?" + urllib.urlencode(args))
      try:
        token_response = file.read()
      finally:
        file.close()
      access_token = cgi.parse_qs(token_response)["access_token"][-1]
      graph = facebook.GraphAPI(access_token)
      user = graph.get_object("me")   
      self.response.out.write(user["id"])
      self.response.out.write(user["name"])

これで、面倒な JavaScript や不要な Cookie を使わずに、自分の Web サイトに「Facebook でログイン」できます。Web サイトで「Facebook でログイン」を有効にしたいと考えていました。Cookie や JavaScript がなくても動作するはずですが、最初にやらせようとするのは Javascript と Cookie です。そこで、Cookie や JavaScript を使用せずに OAuth 2.0 だけで動作するように見えるソリューションを作成しました。私の「ソリューション」について何か言っていただけますか? 私が探している実用的な用途は、FBユーザーが私のウェブサイトで何をしたかという単純な機能を有効にし、Facebookアカウントが標準化されている方法でログインできるようにすることです。

javascript SDK や Cookie がなくても動作するはずだと思ったのですが、そのようです。この「ソリューション」の長所と短所を教えてください。Javascript + Cookie よりもはるかに優れていると思いますが、最小限の例が 100% サーバーサイドにあるように見えるのに、なぜ彼らは私たちをだまして javascript と Cookie を使用させるのでしょうか?

ありがとうございました

更新 それは正しいようで、正しく動作し、ユーザーデータをデータストアで使用して、FB 名を JavaScript や Cookie なしで、Python だけでフロントページにレンダリングすることもできます。

class FBUser(db.Model):
    id = db.StringProperty(required=True)
    created = db.DateTimeProperty(auto_now_add=True)
    updated = db.DateTimeProperty(auto_now=True)
    name = db.StringProperty(required=True)
    profile_url = db.StringProperty()
    access_token = db.StringProperty(required=True)
    name = db.StringProperty(required=True)
    picture = db.StringProperty()
    email = db.StringProperty()
    friends = db.StringListProperty()
    dirty = db.BooleanProperty()

class I18NPage(I18NHandler):

    def get(self):
    if self.request.get('code'):
          args = dict(
            code = self.request.get('code'),
            client_id = facebookconf.FACEBOOK_APP_ID,
            client_secret = facebookconf.FACEBOOK_APP_SECRET,
            redirect_uri = 'http://www.kewlbusiness.com/',
          )
      logging.debug("client_id"+str(args))
          file = urllib.urlopen("https://graph.facebook.com/oauth/access_token?" + urllib.urlencode(args))
          try:
        logging.debug("reading file")
            token_response = file.read()
        logging.debug("read file"+str(token_response))
          finally:
            file.close()
          access_token = cgi.parse_qs(token_response)["access_token"][-1]
          graph = main.GraphAPI(access_token)
          user = graph.get_object("me")   #write the access_token to the datastore
      fbuser = main.FBUser.get_by_key_name(user["id"])
          logging.debug("fbuser "+str(fbuser))

          if not fbuser:
            fbuser = main.FBUser(key_name=str(user["id"]),
                                id=str(user["id"]),
                                name=user["name"],
                                profile_url=user["link"],
                                access_token=access_token)
            fbuser.put()
          elif fbuser.access_token != access_token:
            fbuser.access_token = access_token
            fbuser.put()
           self.render_jinja(
                'home_jinja',request=self.request,fbuser=user,...

facebook ユーザー用の変数 fbuser と google ユーザー用の変数 user を使用すると、バグのある不要な javascript + cookie なしで、web サイトに facebook を使用できるようになりました。

これで、Web サイトから Facebook の名前をレンダリングして表示できるようになりました。これは、最終的に JavaScript に依存せず、Cookie を必要としない方法で動作するようになったことを意味します。

サーバー側の OAuth 2.0 が最もクリーンなソリューションであるのに、ドキュメントで javascript + cookie が推奨されているのはなぜですか? JavaScript を使用するか Cookie を使用するかに依存しないため、これが最善の解決策であることに同意しますか?

他の人がサーバーコードでログアウトできず、Javascript SDK に頼る必要があり、JavaScript なしで動作する必要があり、動作する必要があることが要件である可能性があるため、デバッグを行って見つけましたクッキーを「クリア」し、クッキーの名前を変更する必要がありましたが、それは機能しますが、コメントをお願いしたり、私のプロジェクトがこれをどのように解決したと思うかをテストしたりします。このようなログアウト リンクは機能するはずですが、機能しません。2回ログアウトすると機能します。これが修正できるので奇妙なバグですが、ログアウトに2回目のヒットが必要になる理由はまだわかりません。

https://www.facebook.com/logout.php?next=http://www.myappengineproject.com&access_token=AAACVewZBArF4BACUDwnDap5OrQQ5dx0jsHEKPJkIJJ8GdXlYdni5K50xKw6s8BSIDZCpKBtVWF9maHMoJeF9ZCRRYM1zgZD

OAuth 2.0 サーバーサイドのソリューションで JavaScript を完全に回避しようとしたのは私だけではなかったようです。人々はすべてを行うことができましたが、ログアウトできませんでした:

Facebook Oauth ログアウト

Facebook での OAuth 2.0 の公式ドキュメントには次のように書かれています。

ユーザーを次の URL に誘導することで、Facebook セッションからユーザーをログアウトさせることができます。

https://www.facebook.com/logout.php?next=YOUR_URL&access_token=ACCESS_TOKEN

YOUR_URL は、デベロッパー アプリで定義されているサイト ドメインの URL である必要があります。

サーバー側ですべてを実行したかったのですが、ログアウト リンクが機能しないように、推奨されるリンク方法が Cookie を残すことがわかりました https://www.facebook.com/logout.php?next=http://{{host}}&access_token={{current_user.access_token}} 。これは私にとって変化していて、ドキュメントがあまりなかったので、ハイゼンバグのように思えました。とにかく、Cookieを操作するハンドラーを使用して機能を実現できるように思われたため、実際にはユーザーはログアウトされます。

class LogoutHandler(webapp2.RequestHandler):
    def get(self):
        self.set_cookie("fbsr_" + facebookconf.FACEBOOK_APP_ID, None, expires=time.time() - 86400)
        self.redirect("/")
    def set_cookie(self, name, value, expires=None):

        if value is None:
            value = 'deleted'
            expires = datetime.timedelta(minutes=-50000)
        jar = Cookie.SimpleCookie()
        jar[name] = value
        jar[name]['path'] = '/'
        if expires:
            if isinstance(expires, datetime.timedelta):
                expires = datetime.datetime.now() + expires
            if isinstance(expires, datetime.datetime):
                expires = expires.strftime('%a, %d %b %Y %H:%M:%S')
            jar[name]['expires'] = expires
        self.response.headers.add_header(*jar.output().split(': ', 1))

したがって、ハンドラーを /auth/logout にマッピングし、これをリンクに設定すると、ユーザーがサイトから効果的にログアウトされます (Facebook からユーザーをログアウトせずに、うまくいけばテストされていません)。

私のコードの他の部分は、Oauth 通信の OAuth トークンと Cookie ルックアップを処理しています。

def get(self):
    fbuser=None
    profile = None
    access_token = None
    accessed_token = None
    logout = False
    if self.request.get('code'):
      args = dict(
        code = self.request.get('code'),
        client_id = facebookconf.FACEBOOK_APP_ID,
        client_secret = facebookconf.FACEBOOK_APP_SECRET,
        redirect_uri = 'http://self.get_host()/',
      )
      file = urllib.urlopen("https://graph.facebook.com/oauth/access_token?" + urllib.urlencode(args))
      try:
        token_response = file.read()
      finally:
        file.close()
      access_token = cgi.parse_qs(token_response)["access_token"][-1]
      graph = main.GraphAPI(access_token)
      user = graph.get_object("me")   #write the access_token to the datastore
      fbuser = main.FBUser.get_by_key_name(user["id"])
      logging.debug("fbuser "+fbuser.name)

      if not fbuser:
        fbuser = main.FBUser(key_name=str(user["id"]),
                            id=str(user["id"]),
                            name=user["name"],
                            profile_url=user["link"],
                            access_token=access_token)
        fbuser.put()
      elif fbuser.access_token != access_token:
        fbuser.access_token = access_token
        fbuser.put()

    current_user = main.get_user_from_cookie(self.request.cookies, facebookconf.FACEBOOK_APP_ID, facebookconf.FACEBOOK_APP_SECRET)
    if current_user:
      graph = main.GraphAPI(current_user["access_token"])
      profile = graph.get_object("me")
      accessed_token = current_user["access_token"]

ログインは基本的にルートリクエストハンドラーの上記のコードであるため、ログインハンドラーは作成しませんでした。私のユーザークラスは次のとおりです。

class FBUser(db.Model):
    id = db.StringProperty(required=True)
    created = db.DateTimeProperty(auto_now_add=True)
    updated = db.DateTimeProperty(auto_now=True)
    name = db.StringProperty(required=True)
    profile_url = db.StringProperty()
    access_token = db.StringProperty(required=True)
    name = db.StringProperty(required=True)
    picture = db.StringProperty()
    email = db.StringProperty()

私は 2 つの基本的なプロバイダーを一緒にモックし ここに画像の説明を入力 ました。Facebook ユーザーには変数 current_user を使用し、Google ユーザーには変数 user を使用し、ログイン中のユーザーには変数 fbuser を使用するため、Cookie が一致しません。

私が使用する Cookie ルックアップ コードは次のとおりです。私はそれを理解していると思います。

def get_user_from_cookie(cookies, app_id, app_secret):
    """Parses the cookie set by the official Facebook JavaScript SDK.

    cookies should be a dictionary-like object mapping cookie names to
    cookie values.

    If the user is logged in via Facebook, we return a dictionary with the
    keys "uid" and "access_token". The former is the user's Facebook ID,
    and the latter can be used to make authenticated requests to the Graph API.
    If the user is not logged in, we return None.

    Download the official Facebook JavaScript SDK at
    http://github.com/facebook/connect-js/. Read more about Facebook
    authentication at http://developers.facebook.com/docs/authentication/.
    """
    logging.debug('getting user by cookie')
    cookie = cookies.get("fbsr_" + app_id, "")
    if not cookie:
        logging.debug('no cookie found')
        return None
    logging.debug('cookie found')
    response = parse_signed_request(cookie, app_secret)
    if not response:
        logging.debug('returning none')
        return None

    args = dict(
        code = response['code'],
        client_id = app_id,
        client_secret = app_secret,
        redirect_uri = '',
    )

    file = urllib.urlopen("https://graph.facebook.com/oauth/access_token?" + urllib.urlencode(args))
    try:
        token_response = file.read()
    finally:
        file.close()

    access_token = cgi.parse_qs(token_response)["access_token"][-1]
    logging.debug('returning cookie')
    return dict(
        uid = response["user_id"],
        access_token = access_token,
    )

これを解決するために Cookie を学ばなければならなかったので、もっとコメントしていただければ幸いです。ウェルカム メッセージの出力には 3 つの変数が必要でした。1 つは Google ユーザー用、もう 1 つはログインしている Facebook ユーザー用、変数 fbuser は回答に記載されているケース用です。

JavaScript/Cookie は、新しいユーザーを認証しようとするときに使用されます。それはデータベースに存在せず、彼の accessToken もありません。

だから私は3つの変数を使わなければなりませんでした.2つの変数だけでそれを行うことができますか?

    {% if user or current_user or fbuser %}
        <div id="user-ident">
            <span>{% trans %}Welcome,{% endtrans %} <b>{{ current_user.name }}{% if not current_user and user %}{{ user.nickname() }}{% endif %}{% if not current_user and not user and fbuser %}{{ fbuser.name }}{% endif %}</span>
        </div>
        {% endif %}
4

2 に答える 2

1

これを見つけました。見栄えも良く、fb以外にも対応しています。https://code.google.com/p/gae-simpleauth/

于 2014-04-16T12:01:31.330 に答える
1

JavaScript/Cookie は、新しいユーザーを認証しようとするときに使用されます。それはデータベースに存在せず、彼の accessToken もありません。

ユーザーの accessToken を取得すると、任意のプログラミング言語から HTTP 経由で、必要に応じて Cookie や JavaScript を使用せずに Facebook API にアクセスできます。たとえば、Python クライアントがあります: http://github.com/pythonforfacebook/facebook-sdk (以前はhttps://github.com/facebook/python-sdk )

于 2011-11-23T11:23:07.807 に答える