Как включить Facebook OAuth 2.0 полностью на стороне сервера?

Я в основном хочу сохранить facebook ID данного пользователя, чтобы я мог получать больше материала через Facebook. В идеале я хочу решение, которое не использует ни javascript, ни cookie, только serveride, но там не было примера, только указания, поэтому я собрал один, который мы можем обсудить. Вот код, который, как я думаю, работает, когда я просто связываю пользователя с диалогом 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 и куки, которые нам не нужны. Я хотел включить "вход с Facebook" для моего сайта. Это должно работать без cookies и без javascript, но первое, что они пытаются заставить вас сделать, это Javascript и cookies. Поэтому я сделал решение, которое, кажется, работает без куки и без javascript, просто OAuth 2.0: Можете ли вы сказать что-нибудь о моем "решении"? Практическое применение, которое я ищу, - это включение простой функции, которая показывает, что пользователь FB сделал на моем сайте, и разрешение учетным записям facebook входить в систему способом, который становится стандартным.

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

Спасибо

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

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

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

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

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

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

Facebook Oauth Logout

В официальной документации по OAuth 2.0 с Facebook говорится:

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

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

YOUR_URL должен быть URL в домене вашего сайта, как определено в приложении для разработчиков. Developer App.

Я хотел сделать все на стороне сервера и обнаружил, что предложенный способ ссылки оставляет куки, так что ссылка на выход не работает: 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 токены и поиск куки для 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"]

Я не делал loginhandler, так как login в основном является кодом выше в моем корневом обработчике запроса. Мой класс пользователя выглядит следующим образом:

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.

Код поиска куки, который я использую, следующий, и я думаю, что понимаю его и что он делает то, что я хочу:

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

Мне пришлось изучить куки, чтобы решить это, и я надеюсь, что вы сможете прокомментировать больше. Для вывода приветственного сообщения требовалось 3 переменные, одна для пользователя google, одна для вошедшего пользователя facebook и переменная fbuser для случая, упомянутого в ответе:

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

Поэтому мне пришлось использовать 3 переменные, может быть, вы можете сделать это только с 2 переменными?

    {% if user or current_user or fbuser %}
        
{% trans %}Welcome,{% endtrans %} {{ current_user.name }}{% if not current_user and user %}{{ user.nickname() }}{% endif %}{% if not current_user and not user and fbuser %}{{ fbuser.name }}{% endif %}
{% endif %}

8
задан Community 23 May 2017 в 12:01
поделиться