栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

将Google OAuth2与Flask结合使用

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

将Google OAuth2与Flask结合使用

另一个答案提到了Flask-Rauth,但是没有详细介绍如何使用它。有一些特定于Google的陷阱,但是我终于实现了它,并且效果很好。我将其与Flask-
Login集成在一起,因此可以使用有用的糖(例如)装饰我的视图

@login_required

我希望能够支持多个OAuth2提供程序,因此部分代码是通用的,并基于Miguel
Grinberg在此处有关通过Facebook和Twitter支持OAuth2的出色文章。

首先,将来自Google的特定Google身份验证信息添加到应用程序的配置中:

GOOGLE_LOGIN_CLIENT_ID = "<your-id-ending-with>.apps.googleusercontent.com"GOOGLE_LOGIN_CLIENT_SECRET = "<your-secret>"OAUTH_CREDENTIALS={        'google': { 'id': GOOGLE_LOGIN_CLIENT_ID, 'secret': GOOGLE_LOGIN_CLIENT_SECRET        }}

在创建应用程序时(在我的示例中,是模块的

__init__.py
):

app = Flask(__name__)app.config.from_object('config')

在您的应用模块中,创建

auth.py

from flask import url_for, current_app, redirect, requestfrom rauth import OAuth2Serviceimport json, urllib2class OAuthSignIn(object):    providers = None    def __init__(self, provider_name):        self.provider_name = provider_name        credentials = current_app.config['OAUTH_CREDENTIALS'][provider_name]        self.consumer_id = credentials['id']        self.consumer_secret = credentials['secret']    def authorize(self):        pass    def callback(self):        pass    def get_callback_url(self):        return url_for('oauth_callback', provider=self.provider_name,  _external=True)    @classmethod    def get_provider(self, provider_name):        if self.providers is None: self.providers={} for provider_class in self.__subclasses__():     provider = provider_class()     self.providers[provider.provider_name] = provider        return self.providers[provider_name]class GoogleSignIn(OAuthSignIn):    def __init__(self):        super(GoogleSignIn, self).__init__('google')        googleinfo = urllib2.urlopen('https://accounts.google.com/.well-known/openid-configuration')        google_params = json.load(googleinfo)        self.service = OAuth2Service(     name='google',     client_id=self.consumer_id,     client_secret=self.consumer_secret,     authorize_url=google_params.get('authorization_endpoint'),     base_url=google_params.get('userinfo_endpoint'),     access_token_url=google_params.get('token_endpoint')        )    def authorize(self):        return redirect(self.service.get_authorize_url( scope='email', response_type='pre', redirect_uri=self.get_callback_url()) )    def callback(self):        if 'pre' not in request.args: return None, None, None        oauth_session = self.service.get_auth_session(     data={'pre': request.args['pre'],'grant_type': 'authorization_pre','redirect_uri': self.get_callback_url()          },     deprer = json.loads        )        me = oauth_session.get('').json()        return (me['name'],     me['email'])

这将创建一个

OAuthSignIn
可以子类化的通用类。Google子类从Google发布的信息列表(此处为JSON格式)中提取信息。这些信息会随时更改,因此这种方法将确保它始终是最新的。这种限制之一是,如果在初始化Flask应用程序(导入的模块)时服务器上没有Internet连接,则将无法正确实例化它。这几乎永远不会成为问题,但是在配置数据库中存储最新的值以解决这种情况是个好主意。

最后,该类

name,email
callback()
函数中返回一个元组。Google实际上会返回更多信息,包括Google+个人资料(如果有)。检查返回的字典
oauth_session.get('').json()
以查看全部内容。如果
authorize()
您在函数中扩展了范围(对于我的应用程序来说
email
已足够),则可以通过Google
API访问更多信息。

接下来,编写 视图 以将它们捆绑在一起:

from flask.ext.login import login_user, logout_user, current_user, login_required@app.route('/authorize/<provider>')def oauth_authorize(provider):    # Flask-Login function    if not current_user.is_anonymous():        return redirect(url_for('index'))    oauth = OAuthSignIn.get_provider(provider)    return oauth.authorize()@app.route('/callback/<provider>')def oauth_callback(provider):    if not current_user.is_anonymous():        return redirect(url_for('index'))    oauth = OAuthSignIn.get_provider(provider)    username, email = oauth.callback()    if email is None:        # I need a valid email address for my user identification        flash('Authentication failed.')        return redirect(url_for('index'))    # Look if the user already exists    user=User.query.filter_by(email=email).first()    if not user:        # Create the user. Try and use their name returned by Google,        # but if it is not set, split the email address at the @.        nickname = username        if nickname is None or nickname == "": nickname = email.split('@')[0]        # We can do more work here to ensure a unique nickname, if you         # require that.        user=User(nickname=nickname, email=email)        db.session.add(user)        db.session.commit()    # Log in the user, by default remembering them for their next visit    # unless they log out.    login_user(user, remember=True)    return redirect(url_for('index'))

最后,我的

/login
视图和模板使这一切变为现实:

@app.route('/login', methods=['GET', 'POST'])def login():    if g.user is not None and g.user.is_authenticated():        return redirect(url_for('index'))    return render_template('login.html',     title='Sign In')

login.html:

{% extends "base.html" %}{% block content %}    <div id="sign-in">        <h1>Sign In</h1>        <p>        <a href={{ url_for('oauth_authorize', provider='google') }}><img src="{{ url_for('static', filename='img/sign-in-with-google.png') }}" /></a>    </div>{% endblock %}

确保正确的回调地址已在Google中注册,并且用户只需在您的登录页面上单击“使用Google登录”,它将进行注册并登录。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/639927.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号