当前的纯Python解决方案用于Facebook OAuth?
看起来我并不是唯一一个想要完全避免使用JavaScript来解决OAuth 2.0服务器端问题的人。大家都能做到很多事情,但就是无法登出:
Facebook OAuth2登出不删除fb_ cookie
Facebook的官方文档提到:
你可以通过将用户引导到以下网址来登出他们的Facebook会话:
https://www.facebook.com/logout.php?next=YOUR_URL&access_token=ACCESS_TOKEN
YOUR_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):
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匹配。
1 个回答
我觉得你应该自己在网站上管理用户的登录状态。
你需要手动删除你自己网站上的那个cookie。
最多,这样做会让Facebook的访问令牌失效,前提是这个令牌只是用于会话的,而不是长期使用的离线访问令牌。