Ошибки в моем входе / выходе из системы с facebook
У меня есть забавная и странная ошибка в моем facebook для веб-сайтов. Когда я регистрирую пользователя в facebook, как пользователь, я должен нажать reload, чтобы получить данные пользователя из файла cookie. В противном случае файл cookie не находит пользователя. Если я нажимаю перезагрузить один раз после входа в систему и перезагрузить один раз после выхода из системы, я могу войти и выйти из системы, но это означает, что я делал что-то не так. Не могли бы вы помочь мне найти жучка?
Я использовал код из https://gist.github.com/1190267 и попытался протоколировать поиск файлов 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 from cookie')
cookie = cookies.get("fbsr_" + app_id, "")
if not cookie:
logging.debug('no cookie found')
return None
URL-адрес входа, который я использую, является
https://www.facebook.com/dialog/oauth?client_id=164355773607006&redirect_uri=http://www.koolbusiness.com
И регистрация сценария входа в систему не получает куки до перезагрузки:
"GET /?code=AQB9sh9RWdZsUC_TBWFHLOnOKehjk2ls6kN1ZzCBQRFa6s2ra58e5slaBSI8lYwC5q9Q_f524nsrF-Ts-mgxAHc9xIvt3U7rufKlfJuNfkRbGwgPWZZLCYCwnWHPdb00ANd8QOHB_bYMaI-R_mdI3nQW6bRvpD0DR-SOW-jSvhS8bel4_KlzaBFY3DnYNvxhJgY HTTP/1.1" 200 6248 - "Mozilla/5.0 (X11; Linux x86_64; rv:2.0) Gecko/20100101 Firefox/4.0" "www.koolbusiness.com" ms=80 cpu_ms=0 api_cpu_ms=0 cpm_usd=0.000777 instance=00c61b117c460a7d3f730b42451a4153b74e
D 2011-11-22 07:36:28.182
getting user from cookie
D 2011-11-22 07:36:28.183
no cookie found
Почему? Аналогично, когда я пытаюсь выйти из системы, я должен сделать это дважды, и я не вижу, где ошибка. Я пытался использовать как можно больше серверов, и я подозреваю,что моя проблема заключается в обработке куки. Ты можешь сказать мне, что делать? Моя функция для установки куки:
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))
И вот 2 класса, которые должен сделать это за меня. Как я уже сказал, Все работает, если я перезагружаю, что очень странно, что куки не устанавливается после входа в facebook, и что куки устанавливается просто путем перезагрузки моего индекса pge после входа в FB.
Спасибо
class BaseHandler(webapp2.RequestHandler):
facebook = None
user = None
csrf_protect = True
@property
def current_user(self):
if not hasattr(self, "_current_user"):
self._current_user = None
cookie = facebook.get_user_from_cookie(
self.request.cookies, facebookconf.FACEBOOK_APP_ID, facebookconf.FACEBOOK_APP_SECRET)
logging.debug("logging cookie"+str(cookie))
if cookie:
# Store a local instance of the user data so we don't need
# a round-trip to Facebook on every request
user = FBUser.get_by_key_name(cookie["uid"])
logging.debug("user "+str(user))
if not user:
graph = facebook.GraphAPI(cookie["access_token"])
profile = graph.get_object("me")
user = FBUser(key_name=str(profile["id"]),
id=str(profile["id"]),
name=profile["name"],
profile_url=profile["link"],
access_token=cookie["access_token"])
user.put()
elif user.access_token != cookie["access_token"]:
user.access_token = cookie["access_token"]
user.put()
self._current_user = user
return self._current_user
@property
def current_sender(self):
if not hasattr(self, "_current_sender"):
self._current_sender = None
host=os.environ.get('HTTP_HOST', os.environ['SERVER_NAME'])
if host.find('.br') > 0:
sender = 'info@montao.com.br'
else:
sender = 'admin@koolbusiness.com'
self._current_sender = sender
return self._current_sender
@property
def current_logo(self):
if not hasattr(self, "_current_logo"):
self._current_logo = None
self._current_logo = os.environ.get('HTTP_HOST', os.environ['SERVER_NAME'])
return self._current_logo
def initialize(self, request, response):
"""General initialization for every request"""
super(BaseHandler, self).initialize(request, response)
try:
self.init_facebook()
self.init_csrf()
self.response.headers['P3P'] = 'CP=HONK' # iframe cookies in IE
except Exception, ex:
self.log_exception(ex)
raise
def handle_exception(self, ex, debug_mode):
"""Invoked for unhandled exceptions by webapp"""
self.log_exception(ex)
self.render('error',
trace=traceback.format_exc(), debug_mode=debug_mode)
def log_exception(self, ex):
"""Internal logging handler to reduce some App Engine noise in errors"""
msg = ((str(ex) or ex.__class__.__name__) +
': n' + traceback.format_exc())
if isinstance(ex, urlfetch.DownloadError) or
isinstance(ex, DeadlineExceededError) or
isinstance(ex, CsrfException) or
isinstance(ex, taskqueue.TransientError):
logging.warn(msg)
else:
logging.error(msg)
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 render_jinja(self, name, **data):
logo = 'Koolbusiness.com'
logo_url = '/_/img/kool_business.png'
analytics = 'UA-3492973-18'
domain = 'koolbusiness'
if get_host().find('.br') > 0:
cookie_django_language = 'pt-br'
logo = 'Montao.com.br'
logo_url = '/_/img/montao_small.gif'
analytics = 'UA-637933-12'
domain = None
elif get_host().find('allt') > 0 and not self.request.get('hl'):
logo = ''
cookie_django_language = 'sv'
elif get_host().find('gralumo') > 0
and not self.request.get('hl'):
cookie_django_language = 'es_AR'
else:
cookie_django_language = self.request.get('hl', '')
if cookie_django_language:
if cookie_django_language == 'unset':
del self.request.COOKIES['django_language']
else:
self.set_cookie('django_language', cookie_django_language)
translation.activate(cookie_django_language)
"""Render a Jinja2 template"""
if not data:
data = {}
data['js_conf'] = json.dumps({
'appId': facebookconf.FACEBOOK_APP_ID,
'canvasName': facebookconf.FACEBOOK_CANVAS_NAME,
'userIdOnServer': self.user.id if self.user else None,
})
data['logged_in_user'] = self.user
data['message'] = self.get_message()
data['csrf_token'] = self.csrf_token
data['canvas_name'] = facebookconf.FACEBOOK_CANVAS_NAME
data['current_user']=self.current_user
gkeys = ''
if os.environ.get('HTTP_HOST'):
url = os.environ['HTTP_HOST']
else:
url = os.environ['SERVER_NAME']
data['user']=users.get_current_user()
data['facebook_app_id']=facebookconf.FACEBOOK_APP_ID
user = users.get_current_user()
data['logout_url']=users.create_logout_url(self.request.uri) if users.get_current_user() else 'https://www.facebook.com/dialog/oauth?client_id='+facebookconf.FACEBOOK_APP_ID+'&redirect_uri='+self.request.uri
host=os.environ.get('HTTP_HOST', os.environ['SERVER_NAME'])
data['host']=host
if host.find('.br') > 0:
logo = 'Montao.com.br'
logo_url = '/_/img/montao_small.gif'
analytics = 'UA-637933-12'
domain = None
else:
logo = 'Koolbusiness.com'
logo_url = '/_/img/kool_business.png'
analytics = 'UA-3492973-18'
domain = 'koolbusiness'
data['domain']=domain
data['analytics']=analytics
data['logo']=logo
data['logo_url']=logo_url
data['admin']=users.is_current_user_admin()
if user:
data['greeting'] = ("Welcome, %s! (<a href="%s">sign out</a>)" %
(user.nickname(), users.create_logout_url("/")))
template = jinja_environment.get_template('templates/'+name+'.html')
self.response.out.write(template.render(data))
"""
self.response.out.write(template.render(
os.path.join(
os.path.dirname(__file__), 'templates', name + '.html'),
data))
"""
def render(self, name, **data):
logo = 'Koolbusiness.com'
logo_url = '/_/img/kool_business.png'
analytics = 'UA-3492973-18'
domain = 'koolbusiness'
if get_host().find('.br') > 0:
cookie_django_language = 'pt-br'
logo = 'Montao.com.br'
logo_url = '/_/img/montao_small.gif'
analytics = 'UA-637933-12'
domain = None
elif get_host().find('allt') > 0 and not self.request.get('hl'):
logo = ''
cookie_django_language = 'sv'
elif get_host().find('gralumo') > 0
and not self.request.get('hl'):
cookie_django_language = 'es_AR'
else:
cookie_django_language = self.request.get('hl', '')
if cookie_django_language:
if cookie_django_language == 'unset':
del self.request.COOKIES['django_language']
else:
self.set_cookie('django_language', cookie_django_language)
translation.activate(cookie_django_language)
"""Render a template"""
if not data:
data = {}
data['js_conf'] = json.dumps({
'appId': facebookconf.FACEBOOK_APP_ID,
'canvasName': facebookconf.FACEBOOK_CANVAS_NAME,
'userIdOnServer': self.user.id if self.user else None,
})
data['logged_in_user'] = self.user
data['message'] = self.get_message()
data['csrf_token'] = self.csrf_token
data['canvas_name'] = facebookconf.FACEBOOK_CANVAS_NAME
data['current_user']=self.current_user
data['user']=users.get_current_user()
data['facebook_app_id']=facebookconf.FACEBOOK_APP_ID
user = users.get_current_user()
data['logout_url']=users.create_logout_url(self.request.uri) if users.get_current_user() else 'https://www.facebook.com/dialog/oauth?client_id='+facebookconf.FACEBOOK_APP_ID+'&redirect_uri='+self.request.uri
host=os.environ.get('HTTP_HOST', os.environ['SERVER_NAME'])
data['host']=host
if not host.find('.br') > 0:
logo = 'Koolbusiness.com'
logo_url = '/_/img/kool_business.png'
analytics = 'UA-3492973-18'
domain = 'koolbusiness'
data['domain']=domain
data['analytics']=analytics
data['logo']=logo
data['logo_url']=logo_url
data['admin']=users.is_current_user_admin()
if user:
data['greeting'] = ("Welcome, %s! (<a href="%s">sign out</a>)" %
(user.nickname(), users.create_logout_url("/")))
gkeys = ''
if os.environ.get('HTTP_HOST'):
url = os.environ['HTTP_HOST']
else:
url = os.environ['SERVER_NAME']
self.response.out.write(template.render(
os.path.join(
os.path.dirname(__file__), 'templates', name + '.html'),
data))
def init_facebook(self):
facebook = Facebook()
user = None
# initial facebook request comes in as a POST with a signed_request
if 'signed_request' in self.request.POST:
facebook.load_signed_request(self.request.get('signed_request'))
# we reset the method to GET because a request from facebook with a
# signed_request uses POST for security reasons, despite it
# actually being a GET. in webapp causes loss of request.POST data.
self.request.method = 'GET'
#self.set_cookie(
#'', facebook.user_cookie, datetime.timedelta(minutes=1440))
elif 'u' in self.request.cookies:
facebook.load_signed_request(self.request.cookies.get('u'))
# try to load or create a user object
if facebook.user_id:
user = FBUser.get_by_key_name(facebook.user_id)
if user:
# update stored access_token
if facebook.access_token and
facebook.access_token != user.access_token:
user.access_token = facebook.access_token
user.put()
# refresh data if we failed in doing so after a realtime ping
if user.dirty:
user.refresh_data()
# restore stored access_token if necessary
if not facebook.access_token:
facebook.access_token = user.access_token
if not user and facebook.access_token:
me = facebook.api('/me', {'fields': _USER_FIELDS})
try:
friends = [user['id'] for user in me['friends']['data']]
user = FBUser(key_name=facebook.user_id,
id=facebook.user_id, friends=friends,
access_token=facebook.access_token, name=me['name'],
email=me.get('email'), picture=me['picture'])
user.put()
except KeyError, ex:
pass # ignore if can't get the minimum fields
self.facebook = facebook
self.user = user
def init_csrf(self):
"""Issue and handle CSRF token as necessary"""
self.csrf_token = self.request.cookies.get('c')
if not self.csrf_token:
self.csrf_token = str(uuid4())[:8]
self.set_cookie('c', self.csrf_token)
if self.request.method == 'POST' and self.csrf_protect and
self.csrf_token != self.request.get('_csrf_token'):
raise CsrfException('Missing or invalid CSRF token.')
def set_message(self, **obj):
"""Simple message support"""
self.set_cookie('m', base64.b64encode(json.dumps(obj)) if obj else None)
def get_message(self):
"""Get and clear the current message"""
message = self.request.cookies.get('m')
if message:
self.set_message() # clear the current cookie
return json.loads(base64.b64decode(message))
class Facebook(object):
"""Wraps the Facebook specific logic"""
def __init__(self, app_id=facebookconf.FACEBOOK_APP_ID,
app_secret=facebookconf.FACEBOOK_APP_SECRET):
self.app_id = app_id
self.app_secret = app_secret
self.user_id = None
self.access_token = None
self.signed_request = {}
def api(self, path, params=None, method='GET', domain='graph'):
"""Make API calls"""
if not params:
params = {}
params['method'] = method
if 'access_token' not in params and self.access_token:
params['access_token'] = self.access_token
result = json.loads(urlfetch.fetch(
url='https://' + domain + '.facebook.com' + path,
payload=urllib.urlencode(params),
method=urlfetch.POST,
headers={
'Content-Type': 'application/x-www-form-urlencoded'})
.content)
if isinstance(result, dict) and 'error' in result:
raise FacebookApiError(result)
return result
def load_signed_request(self, signed_request):
"""Load the user state from a signed_request value"""
try:
sig, payload = signed_request.split('.', 1)
sig = self.base64_url_decode(sig)
data = json.loads(self.base64_url_decode(payload))
expected_sig = hmac.new(
self.app_secret, msg=payload, digestmod=hashlib.sha256).digest()
# allow the signed_request to function for upto 1 day
if sig == expected_sig and
data['issued_at'] > (time.time() - 86400):
self.signed_request = data
self.user_id = data.get('user_id')
self.access_token = data.get('oauth_token')
except ValueError, ex:
pass # ignore if can't split on dot
@property
def user_cookie(self):
"""Generate a signed_request value based on current state"""
if not self.user_id:
return
payload = self.base64_url_encode(json.dumps({
'user_id': self.user_id,
'issued_at': str(int(time.time())),
}))
sig = self.base64_url_encode(hmac.new(
self.app_secret, msg=payload, digestmod=hashlib.sha256).digest())
return sig + '.' + payload
@staticmethod
def base64_url_decode(data):
data = data.encode('ascii')
data += '=' * (4 - (len(data) % 4))
return base64.urlsafe_b64decode(data)
@staticmethod
def base64_url_encode(data):
return base64.urlsafe_b64encode(data).rstrip('=')
1 ответ:
Решение: избегайте javascript, избегайте cookies и используйте serverside OAuth 2.0, и гораздо проще следить за тем, что происходит, и это работает:
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.koolbusiness.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()