当前用于 facebook-oauth 的纯 python 解决方案?

Posted

技术标签:

【中文标题】当前用于 facebook-oauth 的纯 python 解决方案?【英文标题】:Current pure python solution for facebook-oauth? 【发布时间】:2012-01-05 21:46:26 【问题描述】:

看起来我并不是唯一一个试图完全避免使用 javascript 来使用 OAuth 2.0 服务器端的解决方案的人。人们可以做任何事情,但他们无法退出:

Facebook Oauth Logout

Oauth Logout using facebook graph api

Facebook OAuth2 Logout does not remove fb_ cookie

official documentation for OAuth 2.0 with Facebook 说:

您可以让用户退出他们的 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 它会重定向,但不会将用户从我的网站中注销。这似乎是一个 Heisenbug,因为这对我来说正在改变并且没有太多文档。无论如何,我似乎能够使用操纵 cookie 的处理程序来实现该功能,从而实际上用户已注销:

class LogoutHandler(webapp2.RequestHandler):
    def get(self):
        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"] 
        self.set_cookie("fbsr_" + facebookconf.FACEBOOK_APP_ID, None, expires=time.time() - 86400)
        self.redirect("https://www.facebook.com/logout.php?next=http://%s&access_token=%s" get_host(), accessed_token)
    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))
    def get_host(self):
        return os.environ.get('HTTP_HOST', os.environ['SERVER_NAME'])

因此,将处理程序映射到 /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 = '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()

我一起模拟了两个基本的提供者 我将变量 current_user 用于 facebook 用户,将变量 user 用于 google 用户,将变量 fbuser 用于正在登录的用户,因此没有 cookie 匹配。

【问题讨论】:

让用户退出您的网站完全取决于您 - 您只需删除您正在使用的会话即可跟踪他们的登录详细信息。外部 API 如何做到这一点? 另外,嗯,有什么问题吗?你似乎只是在描述你做了什么。 默认令牌有效期为2小时,除非您请求offline_access权限。 【参考方案1】:

我相信您应该自己跟踪网站上的身份验证。 您必须自己为 您的 网站取消设置 cookie。

如果 facebook 访问令牌是仅会话令牌而不是离线访问令牌,它最多会使 facebook 访问令牌无效。

【讨论】:

以上是关于当前用于 facebook-oauth 的纯 python 解决方案?的主要内容,如果未能解决你的问题,请参考以下文章

用于计算百分位数的纯 python 实现:这里的 lambda 函数有啥用?

onLongClick 用于 WebView 内的纯文本

存在哪些用于多维数据的纯 Java 库/组件?

用于防止双重提交的纯 Java/JSF 实现

用于 BigQuery UDF 的纯 javascript HTML 解析器

用于可滚动窗格的纯 Java HTML 查看器/渲染器 [关闭]