Как добавить поставщиков OAuth 2.0?

Я мог бы воспроизвести свою ошибку, используя служебную программу OAuth2.0, так что это не javascript, и проблема в том, что я должен перезагрузить, чтобы сделать логин / выход из системы, и я хочу, чтобы он работал без javascript. У меня есть идея, что сделать logout дважды делает logout эффективным, поэтому я могу использовать собственный обработчик запросов для / login и / или / logour или just / sessionchange, который будет делать self.redirect, но это не чистое решение. Может быть, вы можете взглянуть на код и посмотреть, почему я должен выйти дважды, то есть я должен перезагрузить, и могу ли я обойти это с помощью self.redirect ? Я использую файлы cookie правильно, новый файл cookie, или я его смешиваю? Я делаю это как для веб-сайта, так и для приложения FB . Буду рад, если вы придете с любым предложением. Перед тем, как я удалил Javascript, есть фон из двух связанных вопросов. И BTW следует использовать класс Facebook или facebook.py? Я думаю, что я прокомментировал, где установлен старый файл cookie, и что это будет правильно, как только OAuth 2.0 будет обрабатывать мои серверы аутентификации. Можете ли вы прокомментировать или ответить? Заранее спасибо, если вы можете просмотреть и прокомментировать.

Как сделать мой приветственный текст?

Как перезагрузить эту страницу при входе / выходе из системы?

Почему мои странные результаты визуализируют объект пользователя?

login.html

 {% load i18n %} <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>{% trans "Log in" %}</title> <script type="text/javascript"> var _gaq = _gaq || []; _gaq.push(['_setAccount', '{{analytics}}']); _gaq.push(['_trackPageview']); (function() { var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); })(); </script> </head> <body> <div id="fb-root"></div> <script> window.fbAsyncInit = function() { FB.init({ appId : '164355773607006', // App ID channelURL : '//WWW.KOOLBUSINESS.COM/static/channel.html', // Channel File status : true, // check login status cookie : true, // enable cookies to allow the server to access the session oauth : true, // enable OAuth 2.0 xfbml : true // parse XFBML }); // Additional initialization code here }; // Load the SDK Asynchronously (function(d){ var js, id = 'facebook-jssdk'; if (d.getElementById(id)) {return;} js = d.createElement('script'); js.id = id; js.async = true; js.src = "//connect.facebook.net/en_US/all.js"; d.getElementsByTagName('head')[0].appendChild(js); }(document)); </script> <a href="https://www.facebook.com/dialog/oauth?client_id=164355773607006&redirect_uri=http://{{host}}"><img src="/_/img/loginwithfacebook.png"></a> <a href="/_ah/login_redir?claimid=google.com/accounts/o8/id&continue=http://{{host}}"><img src="/_/img/loginwithgoogle.png"></a><br>{% if user %}<a href="{{ logout_url }}" class="logout">Logout Google</a>{% endif %} {% if current_user %}<a href="https://www.facebook.com/logout.php?next=http://{{host}}&access_token={{current_user.access_token}}" onclick="FB.logout()">Logout Facebook</a> {% endif %} {% if current_user %}<a href="/logout" onclick="FB.logout();">Logout Facebook JS</a> {% endif %} </body> </html> class BaseHandler(webapp.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)) logging.debug("username "+str(user.name)) 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 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[u'P3P'] = u'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(u'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__) + u': \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'] = u'/' 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(u': ', 1)) def render(self, name, **data): """Render a template""" if not data: data = {} data[u'js_conf'] = json.dumps({ u'appId': facebookconf.FACEBOOK_APP_ID, u'canvasName': facebookconf.FACEBOOK_CANVAS_NAME, u'userIdOnServer': self.user.id if self.user else None, }) data[u'logged_in_user'] = self.user data[u'message'] = self.get_message() data[u'csrf_token'] = self.csrf_token data[u'canvas_name'] = facebookconf.FACEBOOK_CANVAS_NAME data[u'current_user']=self.current_user data[u'user']=users.get_current_user() data[u'facebook_app_id']=facebookconf.FACEBOOK_APP_ID user = users.get_current_user() data[u'logout_url']=users.create_logout_url(self.request.uri) if users.get_current_user() else 'https://www.facebook.com/dialog/oauth?client_id=164355773607006&redirect_uri='+self.request.uri host=os.environ.get('HTTP_HOST', os.environ['SERVER_NAME']) data[u'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[u'domain']=domain data[u'analytics']=analytics data[u'logo']=logo data[u'logo_url']=logo_url data[u'admin']=users.is_current_user_admin() if user: data[u'greeting'] = ("Welcome, %s! (<a href=\"%s\">sign out</a>)" % (user.nickname(), users.create_logout_url("/"))) 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 u'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 = u'GET' #self.set_cookie( #'u', 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(u'/me', {u'fields': _USER_FIELDS}) try: friends = [user[u'id'] for user in me[u'friends'][u'data']] user = FBUser(key_name=facebook.user_id, id=facebook.user_id, friends=friends, access_token=facebook.access_token, name=me[u'name'], email=me.get(u'email'), picture=me[u'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(u'c') if not self.csrf_token: self.csrf_token = str(uuid4())[:8] self.set_cookie('c', self.csrf_token) if self.request.method == u'POST' and self.csrf_protect and \ self.csrf_token != self.request.POST.get(u'_csrf_token'): raise CsrfException(u'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(u'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=u'GET', domain=u'graph'): """Make API calls""" if not params: params = {} params[u'method'] = method if u'access_token' not in params and self.access_token: params[u'access_token'] = self.access_token result = json.loads(urlfetch.fetch( url=u'https://' + domain + u'.facebook.com' + path, payload=urllib.urlencode(params), method=urlfetch.POST, headers={ u'Content-Type': u'application/x-www-form-urlencoded'}) .content) if isinstance(result, dict) and u'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(u'.', 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[u'issued_at'] > (time.time() - 86400): self.signed_request = data self.user_id = data.get(u'user_id') self.access_token = data.get(u'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({ u'user_id': self.user_id, u'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(u'ascii') data += '=' * (4 - (len(data) % 4)) return base64.urlsafe_b64decode(data) @staticmethod def base64_url_encode(data): return base64.urlsafe_b64encode(data).rstrip('=') 

facebook.py

 #!/usr/bin/env python # # Copyright 2010 Facebook # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Python client library for the Facebook Platform. This client library is designed to support the Graph API and the official Facebook JavaScript SDK, which is the canonical way to implement Facebook authentication. Read more about the Graph API at http://developers.facebook.com/docs/api. You can download the Facebook JavaScript SDK at http://github.com/facebook/connect-js/. If your application is using Google AppEngine's webapp framework, your usage of this module might look like this: user = facebook.get_user_from_cookie(self.request.cookies, key, secret) if user: graph = facebook.GraphAPI(user["access_token"]) profile = graph.get_object("me") friends = graph.get_connections("me", "friends") """ from google.appengine.dist import use_library use_library('django', '1.2') import cgi import hashlib import time import urllib #from django.utils import translation, simplejson as json # Find a JSON parser try: # For Google AppEngine from django.utils import simplejson _parse_json = lambda s: simplejson.loads(s) except ImportError: try: import simplejson _parse_json = lambda s: simplejson.loads(s) except ImportError: import json _parse_json = lambda s: json.loads(s) class GraphAPI(object): """A client for the Facebook Graph API. See http://developers.facebook.com/docs/api for complete documentation for the API. The Graph API is made up of the objects in Facebook (eg, people, pages, events, photos) and the connections between them (eg, friends, photo tags, and event RSVPs). This client provides access to those primitive types in a generic way. For example, given an OAuth access token, this will fetch the profile of the active user and the list of the user's friends: graph = facebook.GraphAPI(access_token) user = graph.get_object("me") friends = graph.get_connections(user["id"], "friends") You can see a list of all of the objects and connections supported by the API at http://developers.facebook.com/docs/reference/api/. You can obtain an access token via OAuth or by using the Facebook JavaScript SDK. See http://developers.facebook.com/docs/authentication/ for details. If you are using the JavaScript SDK, you can use the get_user_from_cookie() method below to get the OAuth access token for the active user from the cookie saved by the SDK. """ def __init__(self, access_token=None): self.access_token = access_token def get_object(self, id, **args): """Fetchs the given object from the graph.""" return self.request(id, args) def get_objects(self, ids, **args): """Fetchs all of the given object from the graph. We return a map from ID to object. If any of the IDs are invalid, we raise an exception. """ args["ids"] = ",".join(ids) return self.request("", args) def get_connections(self, id, connection_name, **args): """Fetchs the connections for given object.""" return self.request(id + "/" + connection_name, args) def put_object(self, parent_object, connection_name, **data): """Writes the given object to the graph, connected to the given parent. For example, graph.put_object("me", "feed", message="Hello, world") writes "Hello, world" to the active user's wall. Likewise, this will comment on a the first post of the active user's feed: feed = graph.get_connections("me", "feed") post = feed["data"][0] graph.put_object(post["id"], "comments", message="First!") See http://developers.facebook.com/docs/api#publishing for all of the supported writeable objects. Most write operations require extended permissions. For example, publishing wall posts requires the "publish_stream" permission. See http://developers.facebook.com/docs/authentication/ for details about extended permissions. """ assert self.access_token, "Write operations require an access token" return self.request(parent_object + "/" + connection_name, post_args=data) def put_wall_post(self, message, attachment={}, profile_id="me"): """Writes a wall post to the given profile's wall. We default to writing to the authenticated user's wall if no profile_id is specified. attachment adds a structured attachment to the status message being posted to the Wall. It should be a dictionary of the form: {"name": "Link name" "link": "http://www.example.com/", "caption": "{*actor*} posted a new review", "description": "This is a longer description of the attachment", "picture": "http://www.example.com/thumbnail.jpg"} """ return self.put_object(profile_id, "feed", message=message, **attachment) def put_comment(self, object_id, message): """Writes the given comment on the given post.""" return self.put_object(object_id, "comments", message=message) def put_like(self, object_id): """Likes the given post.""" return self.put_object(object_id, "likes") def delete_object(self, id): """Deletes the object with the given ID from the graph.""" self.request(id, post_args={"method": "delete"}) def request(self, path, args=None, post_args=None): """Fetches the given path in the Graph API. We translate args to a valid query string. If post_args is given, we send a POST request to the given path with the given arguments. """ if not args: args = {} if self.access_token: if post_args is not None: post_args["access_token"] = self.access_token else: args["access_token"] = self.access_token post_data = None if post_args is None else urllib.urlencode(post_args) file = urllib.urlopen("https://graph.facebook.com/" + path + "?" + urllib.urlencode(args), post_data) try: response = _parse_json(file.read()) finally: file.close() if response.get("error"): raise GraphAPIError(response["error"]["type"], response["error"]["message"]) return response class GraphAPIError(Exception): def __init__(self, type, message): Exception.__init__(self, message) self.type = type ##### NEXT TWO FUNCTIONS PULLED FROM https://github.com/jgorset/facepy/blob/master/facepy/signed_request.py import base64 import hmac def urlsafe_b64decode(str): """Perform Base 64 decoding for strings with missing padding.""" l = len(str) pl = l % 4 return base64.urlsafe_b64decode(str.ljust(l+pl, "=")) def parse_signed_request(signed_request, secret): """ Parse signed_request given by Facebook (usually via POST), decrypt with app secret. Arguments: signed_request -- Facebook's signed request given through POST secret -- Application's app_secret required to decrpyt signed_request """ if "." in signed_request: esig, payload = signed_request.split(".") else: return {} sig = urlsafe_b64decode(str(esig)) data = _parse_json(urlsafe_b64decode(str(payload))) if not isinstance(data, dict): raise SignedRequestError("Pyload is not a json string!") return {} if data["algorithm"].upper() == "HMAC-SHA256": if hmac.new(secret, payload, hashlib.sha256).digest() == sig: return data else: raise SignedRequestError("Not HMAC-SHA256 encrypted!") return {} 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/. """ cookie = cookies.get("fbsr_" + app_id, "") if not cookie: return None response = parse_signed_request(cookie, app_secret) if not response: 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] return dict( uid = response["user_id"], access_token = access_token, ) 

Некоторые следы журнала

 2011-10-18 18:25:07.912 logging cookie{'access_token': 'AAACVewZBArF4BACUDwnDap5OrQQ5dx0sHEKuPJkIJJ8GdXlYdni5K50xKw6s8BSIDZCpKBtVWF9maHMoJeF9ZCRRYM1zgZD', 'uid': u'32740016'} D 2011-10-18 18:25:07.925 user <__main__.FBUser object at 0x39d606ae980b528> D 2011-10-18 18:25:07.925 username Niklas R 

Теперь, глядя на код, который делает это, мне кажется, что я запутываю модуль facebook с переменной facebook, где один из них является классом facebook из примера проекта, а другой – новым рекомендуемым модулем facebook.py:

 class BaseHandler(webapp.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)) logging.debug("username "+str(user.name)) 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 

  • API диаграмм аутентифицируется как пользователь программно
  • Войдите на сайт, войдя в аккаунт Google, используя Python
  • Несанкционированное взаимодействие с API календаря Google v3
  • Вход в Google+ - поток на стороне сервера - Python - Google App Engine
  • поставщик google app engine oauth2
  • Использование Google OAuth2 с Flask
  • Импорт контактов Google с использованием oauth2.0
  • Python не может найти модуль «clientsecrets» при попытке настроить oauth2 в Django с помощью API Google Python
  • One Solution collect form web for “Как добавить поставщиков OAuth 2.0?”

    Как добавить Facebook как поставщика OAuth 2.0: Вот как я делаю «Вход с facebook» для моего сайта с OAuth вместо javascript / cookie, это python только для OAuth 2.0 с Facebook и насколько я могу сказать, что он работает:

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

    Ссылка для входа

    <a href="https://www.facebook.com/dialog/oauth?client_id=164355773607006&redirect_uri=http://{{host}}/"><img src="/_/img/loginwithfacebook.png"></a> который перенаправляет и позволяет мне получить access_token в вышеприведенном методе, а выход из системы прост:

    <a href="https://www.facebook.com/logout.php?next=http://www.koolbusiness.com&access_token={{access_token}}">{% trans "Log out" %}</a>

    Python - лучший язык программирования в мире.