Как да активирам Facebook OAuth 2.0 изцяло от страна на сървъра?

По принцип искам да запазя facebook ID на даден потребител, за да мога да получавам повече материали чрез Facebook. В идеалния случай искам решение, което нито използва javascript, нито бисквитка, само от страна на сървъра, но нямаше пример, само указания, така че събрах едно, което можем да обсъдим. Ето кода, който според мен работи, когато просто свържа потребител към диалоговия прозорец 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“ за моя уебсайт. Трябва да работи без бисквитки и без javascript, но първото нещо, което се опитват да ви накарат да направите, е Javascript и бисквитки. Така че направих решение, което изглежда работи без бисквитки и без javascript, само OAuth 2.0: Можете ли да кажете нещо за моето „решение“? Практическата употреба, която търся, е активиране на проста функция кой FB потребител е направил какво на моя уебсайт и допускане на акаунти във Facebook за влизане по начина, който се стандартизира.

Просто си помислих, че трябва да работи без javascript SDK и без бисквитка и изглежда, че е така. Можете ли да кажете какви са моите предимства и недостатъци с това "решение"? Мисля, че е много по-добро от Javascript + Cookie, така че защо ни подвеждат да използваме javascript и бисквитка, когато минималният пример изглежда 100% сървърен?

Благодаря ти

Актуализация Изглежда правилно и се държи правилно и мога също да използвам потребителските данни с datator и да изобразя 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 и променливата потребител за потребител на google вече ми позволява да използвам facebook за моя уебсайт без бъгове, разхвърлян ненужен javascript + бисквитка.

Сега мога да изобразя и видя името си във facebook от моя уебсайт, което е страхотно, че най-накрая работи както трябва, независимо от javascript и не се нуждае от бисквитка.

Защо документацията препоръчва javascript + бисквитка, когато сървърният OAuth 2.0 е най-чистото решение? Съгласни ли сте, че това е най-доброто решение, тъй като не зависи от това дали използвате javascript или бисквитка?

Актуализация Възможен дублиран въпрос, когато сега видях, че други момчета не могат да излязат със сървърен код, те трябваше да прибегнат до Javascript SDK и изискване може да бъде, че трябва и трябва да работи без javascript така че направих малко отстраняване на грешки и открих, че "изчистването" на бисквитката и трябваше да променя името на бисквитката и въпреки че работи, бих искал вашия коментар и/или да тествам как според вас моят проект е решил това. Връзка за излизане като тази би трябвало да работи, но не става. Ако изляза два пъти, това работи и затова това е странен бъг, тъй като мога да го поправя, но все още не знам какво кара излизането да изисква второ посещение:

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

Изглежда, че не бях единственият, който се опитваше да избегне напълно javascript за решение с OAuth 2.0 сървър. Хората можеха да правят всичко, но не можеха да излязат:

Facebook Oauth излизане

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

Можете да излезете от даден потребител от сесията му във Facebook, като го насочите към следния URL адрес:

https://www.facebook.com/logout.php?next=ВАШИЯ_URL&access_token=ACCESS_TOKEN

YOUR_URL трябва да бъде URL в домейна на вашия сайт, както е дефинирано в приложението за разработчици.

Исках да направя всичко от страна на сървъра и открих, че предложеният начин за свързване оставя бисквитката, така че връзката за излизане да не работи: https://www.facebook.com/logout.php?next=http://{{host}}&access_token={{current_user.access_token}} Пренасочва, но не регистрира потребителя на моя уебсайт. Изглеждаше като Heisenbug, тъй като това се променяше за мен и нямаше много документация. Така или иначе изглежда, че успях да постигна функционалността с манипулатор, който манипулира бисквитката, така че на практика потребителят да излезе от системата:

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 основно е кодът по-горе в моя root манипулатор на заявки. Моят потребителски клас е както следва:

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

Подиграх заедно два основни доставчика въведете описание на изображението тукИ използвам променливата current_user за потребителя на facebook и променливата потребител за потребителя на google и променливата fbuser за потребител, който влиза и следователно няма съвпадение на бисквитка.

Кодът за търсене на бисквитки, който използвам, е следният и мисля, че го разбирам и че прави това, което искам:

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/бисквитките се използват, когато се опитвате да удостоверите нов потребител. Това не съществува във вашата база данни и вие нямате неговия 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 %}

person Niklas R.    schedule 23.11.2011    source източник


Отговори (2)


JavaScript/бисквитките се използват, когато се опитвате да удостоверите нов потребител. Това не съществува във вашата база данни и вие нямате неговия accessToken.

Когато имате потребителски accessToken - можете да получите достъп до Facebook API от всеки език за програмиране, чрез HTTP, без бисквитки/javascript, ако желаете. Има python клиент, например: http://github.com/pythonforfacebook/facebook-sdk (бе https://github.com/facebook/python-sdk)

person Igor Artamonov    schedule 23.11.2011
comment
Благодаря за линка. Този пример беше добър, тъй като това е, което търся за обикновен OAuth и разбирам, че бисквитките се използват за управление на сесии. Мисля, че всичко работи, освен моето излизане и примерът предоставя много удобен logouthandler, тъй като видях, че други хора са се опитвали да направят това без javascript и го намират за сложно - person Niklas R.; 23.11.2011
comment
Logouthandler работи за мен и това беше последният компонент, който ме притесняваше (изход). Връзката, предоставена от facebook, не изчиства бисквитката, така че потребителите да останат влезли - person Niklas R.; 24.11.2011
comment
Късно за мача. Но тази връзка изглежда прекъсната. Актуализираният е: github.com/pythonforfacebook/facebook-sdk - person damzam; 27.12.2012

Намерих това. Изглежда също добре и се грижи за повече от просто fb. https://code.google.com/p/gae-simpleauth/

person Community    schedule 16.04.2014
comment
Това е, което използвам днес и също работи с foursquare. Обмислям сам да опитам да стана доставчик на Oauth, за да мога да добавя сайта си по същия начин, по който добавям друг доставчик. Беше неблагоприятно да правим много различни потребителски модели, но сега все още можем да използваме потребителския модел на webapp2, който е ndb.Expando Предполагам, че може да се разработи simpleauth, така че да можем да добавим доставчик, без дори да преразпределяме нова версия на приложение, идеята ми е твърде запазване на доставчика данни в хранилището за данни, така че да можете да добавите доставчик от администраторска уеб секция. - person Niklas R.; 16.04.2014
comment
интересно уведомете ни как става това. - person ; 17.04.2014