Как включить Facebook OAuth 2.0 полностью на стороне сервера? - PullRequest
8 голосов
/ 23 ноября 2011

Я хочу сохранить идентификатор Facebook данного пользователя, чтобы я мог получать больше материалов через Facebook.В идеале мне нужно решение, которое не использует ни javascript, ни cookie, а только сервер, но не было ни одного примера, только указания, поэтому я собрал одно, которое мы можем обсудить.Вот код, который, я думаю, работает, когда я просто связываю пользователя с диалоговым окном 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"])

Таким образом, я могу «войти через Facebook» для моего сайта без большого количества грязного JavaScript и файлов cookie, которые нам не нужны.Я хотел включить "войти через Facebook" для моего сайта.Он должен работать без файлов cookie и без JavaScript, но первое, что они пытаются заставить вас сделать, - это Javascript и файлы cookie.Итак, я сделал решение, которое, кажется, работает без cookie и без javascript, просто OAuth 2.0: Можете ли вы сказать что-нибудь о моем «решении»?Практическое использование, которое я ищу, - это включить простую функцию, которую пользователь FB делал на моем веб-сайте, и допустить учетные записи Facebook для входа в систему, которая стандартизируется.

Я просто подумал, что она должна работать без javascript SDK ибез печенья и, кажется, это так.Можете ли вы сказать, каковы мои преимущества и недостатки этого «решения»?Я думаю, что это намного лучше, чем Javascript + Cookie, так почему они обманывают нас, чтобы использовать javascript и cookie, когда минимальный пример, кажется, на 100% сервер?

Спасибо

Обновление Кажется правильным и ведет себя правильно, и я также могу использовать userdata с datatore и отображать мое имя 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,...

с переменной fbuserдля пользователя facebook и переменной user для пользователя google теперь разрешает мне использовать facebook для моего сайта без гадкого беспорядочного ненужного javascript + cookie.

Теперь я могу отображать и просматривать мое имя в Facebook с моего сайта, и это здорово, что оно, наконец, работает так, как предполагается независимым от javascript и не нуждается в cookie.

Почему документация рекомендует javascript + cookie, когда серверная OAuth 2.0 является наиболее чистым решением?Согласны ли вы с тем, что это лучшее решение, поскольку оно не зависит от того, используете ли вы javascript или cookie-файл?

Обновление Возможен повторяющийся вопрос, когда я теперь вижу, что другие парни не могутВыйдите из системы с помощью серверного кода, им пришлось прибегнуть к Javascript SDK, и может потребоваться, чтобы он работал и работал без JavaScript, поэтому я выполнил некоторую отладку и обнаружил, что «очистив» файл cookie, мне пришлось изменить имяcookie, и хотя он работает, я хотел бы получить ваш комментарий и / или проверить, как вы думаете, мой проект решил эту проблему.Ссылка на выход из системы, подобная этой, должна работать, но это не так.Если я дважды выхожу из системы, это работает, и поэтому это странная ошибка, так как я мог ее исправить, но я все еще не знаю, для чего для выхода требуется 2-й удар:

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

Похоже, я был не единственным, кто пытался вообще избежать javascript для решения с серверной стороной OAuth 2.0.Люди могли делать все, но не могли выйти из системы:

Выход из Facebook Facebook Oauth

Официальная документация для OAuth 2.0 с Facebook гласит:

Вы можете отключить пользователя от сеанса Facebook, направив его по следующему URL:

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}} Он перенаправляет, но не регистрируетпользователь нашего моего сайта.Это походило на Heisenbug, так как это изменилось для меня, и не было много документации.В любом случае мне казалось, что я смог достичь функциональности с помощью обработчика, который манипулирует 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 и поиск файлов cookie для связи Oauth:

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

Я смоделировал вместе двух основных провайдеров enter image description here И я использую переменную current_user для пользователя facebook и переменную user для пользователя google и переменную 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 переменные: одна для пользователя Google, одна для пользователя, вошедшего в Facebook, и переменная fbuser для случая, упомянутого в ответе:

JavaScript / Cookies используются при попыткеаутентифицировать нового пользователя.Его нет в вашей базе данных, и у вас нет его 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 %}

Ответы [ 2 ]

1 голос
/ 16 апреля 2014

Нашел это. Выглядит хорошо, и он обслуживает больше, чем просто FB. https://code.google.com/p/gae-simpleauth/

1 голос
/ 23 ноября 2011

JavaScript / Cookies используются, когда вы пытаетесь аутентифицировать нового пользователя. Этого нет в вашей базе данных, и у вас нет его accessToken.

Когда у вас есть accessToken пользователя - вы можете получить доступ к Facebook API с любого языка программирования, через HTTP, без куки-файлов / JavaScript, если хотите. Существует клиент Python, например: http://github.com/pythonforfacebook/facebook-sdk (было https://github.com/facebook/python-sdk)

...