62 votes

À l'aide de Google OAuth2 avec Flacon

Quelqu'un peut-il m'indiquer un exemple complet pour l'authentification avec un compte Google à l'aide de OAuth2 et la Fiole, et pas sur App Engine?

Je suis en train de demander aux utilisateurs de donner accès à Google Agenda, et ensuite utiliser cet accès pour récupérer des informations à partir du calendrier et le processus encore plus loin. J'ai aussi besoin de stocker et plus tard actualiser la OAuth2 jetons.

J'ai regardé Google oauth2client de la bibliothèque et peuvent obtenir de la danse a commencé à récupérer le code d'autorisation, mais je suis un peu perdue à partir de là. La recherche chez Google OAuth 2.0 Aire de jeu, je comprends que j'ai besoin de demander l'actualisation jeton jeton d'accès, mais les exemples fournis dans la bibliothèque sont pour App Engine et Django seulement.

J'ai aussi essayé d'utiliser le Flacon de OAuth module qui contient des références à OAuth2, mais je ne vois pas de moyen d'échange le code d'autorisation que ce soit.

Je pourrais probablement de la main de code à la demande, mais beaucoup préfèrent utiliser ou adapter l'existant module python qui fait des demandes facile, gère correctement les réponses possibles et peut-être même l'aide dans le stockage de jetons.

Est-il une telle chose?

33voto

JackLeo Points 1436

J'ai cherché un peu sur l'utilisation de bibliothèques différentes, mais tous semblaient éther overkill dans un certain sens (vous pouvez l'utiliser sur n'importe quelle plateforme, mais pour cela vous avez besoin d'une tonne de code) ou de la documentation n'a pas expliqué ce que je voulais. Longue histoire courte, j'ai écrit à partir de zéro ainsi la compréhension des processus d'authentification vrai API de Google. Il n'est pas aussi difficile qu'il y paraît. Fondamentalement, vous devez suivre https://developers.google.com/accounts/docs/OAuth2WebServer lignes directrices et c'est tout. Pour cela, vous aurez également besoin de s'inscrire à https://code.google.com/apis/console/ pour générer des informations d'identification et d'enregistrer vos liens. J'ai utilisé de simples sous-domaine qui pointe sur mon IP du bureau, car il ne permet de domaines.

Pour la connexion de l'utilisateur, la gestion et les sessions, j'ai utilisé ce plugin pour flacon http://packages.python.org/Flask-Login/ - il y aura un peu de code sur cette base.

Donc, la première chose à première vue "index":

from flask import render_template
from flask.ext.login import current_user
from flask.views import MethodView

from myapp import app


class Index(MethodView):
    def get(self):
        # check if user is logged in
        if not current_user.is_authenticated():
            return app.login_manager.unauthorized()

        return render_template('index.html')

donc, ce ne sera pas ouverte jusqu'à ce que nous aurons de l'utilisateur authentifié. Parler des utilisateurs de l'utilisateur modèle:

from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy import Column, Integer, DateTime, Boolean, String

from flask.ext.login import UserMixin
from myapp.metadata import Session, Base


class User(Base):
    __tablename__ = 'myapp_users'

    id = Column(Integer, primary_key=True)
    email = Column(String(80), unique=True, nullable=False)
    username = Column(String(80), unique=True, nullable=False)

    def __init__(self, email, username):
        self.email = email
        self.username = username

    def __repr__(self):
        return "<User('%d', '%s', '%s')>" \
                % (self.id, self.username, self.email)

    @classmethod
    def get_or_create(cls, data):
        """
        data contains:
            {u'family_name': u'Surname',
            u'name': u'Name Surname',
            u'picture': u'https://link.to.photo',
            u'locale': u'en',
            u'gender': u'male',
            u'email': u'propper@email.com',
            u'birthday': u'0000-08-17',
            u'link': u'https://plus.google.com/id',
            u'given_name': u'Name',
            u'id': u'Google ID',
            u'verified_email': True}
        """
        try:
            #.one() ensures that there would be just one user with that email.
            # Although database should prevent that from happening -
            # lets make it buletproof
            user = Session.query(cls).filter_by(email=data['email']).one()
        except NoResultFound:
            user = cls(
                    email=data['email'],
                    username=data['given_name'],
                )
            Session.add(user)
            Session.commit()
        return user

    def is_active(self):
        return True

    def is_authenticated(self):
        """
        Returns `True`. User is always authenticated. Herp Derp.
        """
        return True

    def is_anonymous(self):
        """
        Returns `False`. There are no Anonymous here.
        """
        return False

    def get_id(self):
        """
        Assuming that the user object has an `id` attribute, this will take
        that and convert it to `unicode`.
        """
        try:
            return unicode(self.id)
        except AttributeError:
            raise NotImplementedError("No `id` attribute - override get_id")

    def __eq__(self, other):
        """
        Checks the equality of two `UserMixin` objects using `get_id`.
        """
        if isinstance(other, UserMixin):
            return self.get_id() == other.get_id()
        return NotImplemented

    def __ne__(self, other):
        """
        Checks the inequality of two `UserMixin` objects using `get_id`.
        """
        equal = self.__eq__(other)
        if equal is NotImplemented:
            return NotImplemented
        return not equal

Il y a probablement quelque chose de mal avec UserMixin, mais je vais faire face à ce dernier. Votre modèle utilisateur va regarder différemment, il suffit de le rendre compatible avec le flacon de connexion.

Donc ce qui est à gauche de l'authentification elle-même. J'ai mis pour flask-login que la connexion view est - 'login'. Login vue affiche le code html avec le bouton de connexion qui pointe vers google - google redirige vers Auth vue. Il devrait être possible juste pour rediriger les utilisateurs de google dans le cas du site web uniquement pour les utilisateurs enregistrés.

import logging
import urllib
import urllib2
import json

from flask import render_template, url_for, request, redirect
from flask.views import MethodView
from flask.ext.login import login_user

from myapp import settings
from myapp.models import User


logger = logging.getLogger(__name__)


class Login(BaseViewMixin):
    def get(self):
        logger.debug('GET: %s' % request.args)
        params = {
            'response_type': 'code',
            'client_id': settings.GOOGLE_API_CLIENT_ID,
            'redirect_uri': url_for('auth', _external=True),
            'scope': settings.GOOGLE_API_SCOPE,
            'state': request.args.get('next'),
        }
        logger.debug('Login Params: %s' % params)
        url = settings.GOOGLE_OAUTH2_URL + 'auth?' + urllib.urlencode(params)

        context = {'login_url': url}
        return render_template('login.html', **context)


class Auth(MethodView):
    def _get_token(self):
        params = {
            'code': request.args.get('code'),
            'client_id': settings.GOOGLE_API_CLIENT_ID,
            'client_secret': settings.GOOGLE_API_CLIENT_SECRET,
            'redirect_uri': url_for('auth', _external=True),
            'grant_type': 'authorization_code',
        }
        payload = urllib.urlencode(params)
        url = settings.GOOGLE_OAUTH2_URL + 'token'

        req = urllib2.Request(url, payload)  # must be POST

        return json.loads(urllib2.urlopen(req).read())

    def _get_data(self, response):
        params = {
            'access_token': response['access_token'],
        }
        payload = urllib.urlencode(params)
        url = settings.GOOGLE_API_URL + 'userinfo?' + payload

        req = urllib2.Request(url)  # must be GET

        return json.loads(urllib2.urlopen(req).read())

    def get(self):
        logger.debug('GET: %s' % request.args)

        response = self._get_token()
        logger.debug('Google Response: %s' % response)

        data = self._get_data(response)
        logger.debug('Google Data: %s' % data)

        user = User.get_or_create(data)
        login_user(user)
        logger.debug('User Login: %s' % user)
        return redirect(request.args.get('state') or url_for('index'))

Donc, tout est découpé de deux parties - une pour google jeton en _get_token. D'autres pour l'utilisation et la récupération de base de données de l'utilisateur en _get_data.

Mon fichier de paramètres contient:

GOOGLE_API_CLIENT_ID = 'myid.apps.googleusercontent.com'
GOOGLE_API_CLIENT_SECRET = 'my secret code'
GOOGLE_API_SCOPE = 'https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email'
GOOGLE_OAUTH2_URL = 'https://accounts.google.com/o/oauth2/'
GOOGLE_API_URL = 'https://www.googleapis.com/oauth2/v1/'

Gardez à l'esprit que les points de vue doit avoir l'adresse de l'url attaché à l'application j'ai donc utiliser cette urls.py le fichier afin que je puisse suivre mon point de vue plus facilement et importer moins de choses à gourde application de création de fichier:

from myapp import app
from myapp.views.auth import Login, Auth
from myapp.views.index import Index


urls = {
    '/login/': Login.as_view('login'),
    '/auth/': Auth.as_view('auth'),
    '/': Index.as_view('index'),
}

for url, view in urls.iteritems():
    app.add_url_rule(url, view_func=view)

Tout cela rend le travail de Google autorisation dans le Flacon. Si vous copiez collez - il pourrait prendre un certain raccommoder avec flacon de connexion de la documentation et de SQLAlchemy mappages, mais l'idée est là.

19voto

Peter Hudec Points 606

Donner Authomatic un essai (je suis le responsable de ce projet). Il est très simple à utiliser, fonctionne avec toute Python cadre et prend en charge 16 OAuth 2.0, 10 OAuth 1.0 fournisseurs et OpenID.

Voici un exemple simple sur la façon d'authentifier un utilisateur Google et d' obtenir son/sa liste de vidéos sur YouTube:

# main.py

from flask import Flask, request, make_response, render_template
from authomatic.adapters import WerkzeugAdapter
from authomatic import Authomatic
from authomatic.providers import oauth2


CONFIG = {
    'google': {
        'class_': oauth2.Google,
        'consumer_key': '########################',
        'consumer_secret': '########################',
        'scope': oauth2.Google.user_info_scope + ['https://gdata.youtube.com'],
    },
}

app = Flask(__name__)
authomatic = Authomatic(CONFIG, 'random secret string for session signing')


@app.route('/login/<provider_name>/', methods=['GET', 'POST'])
def login(provider_name):
    response = make_response()

    # Authenticate the user
    result = authomatic.login(WerkzeugAdapter(request, response), provider_name)

    if result:
        videos = []
        if result.user:
            # Get user info
            result.user.update()

            # Talk to Google YouTube API
            if result.user.credentials:
                response = result.provider.access('https://gdata.youtube.com/'
                    'feeds/api/users/default/playlists?alt=json')
                if response.status == 200:
                    videos = response.data.get('feed', {}).get('entry', [])

        return render_template(user_name=result.user.name,
                               user_email=result.user.email,
                               user_id=result.user.id,
                               youtube_videos=videos)
    return response


if __name__ == '__main__':
    app.run(debug=True)

Il est également très simple Flacon tutoriel qui montre comment authentifier un utilisateur par Facebook et Twitter et de parler à leurs Api pour lire le mode d'échanges de news.

1voto

bluemoon Points 109

Flacon-oauth est probablement votre meilleur pari pour un flacon de manière spécifique de le faire, autant que je sache, il ne supporte pas de jeton rafraîchissant, mais il fonctionne avec Facebook, nous l'utilisons pour cela et c'est oauth 2. Si elle n'a pas besoin d'être en flacon spécifique que vous pourriez regarder demandes-oauth

1voto

emning Points 146

On dirait le nouveau module de Flacon Rauth est la réponse à cette question:

En flacon de Rauth est un Flacon d'extensions qui vous permet d'interagir facilement avec OAuth 2.0, OAuth 1.0 a, et Ofly les applications compatibles. [...] Cela signifie que, en Flacon de Rauth permettra aux utilisateurs de votre Flacon de site web pour vous connecter à des services web externes (c'est à dire l'API Twitter, Facebook API Graphique, GitHub, etc).

Voir: Flacon-Rauth

0voto

Sean Lynch Points 1890

Jetez un oeil à Gourde-Social, qui est construit en Flacon de Sécurité

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X