无法通过Requests-OAuthlib构建Google OAuth2与Flask一起使用

问题描述

我尝试使用flask登录构建gooogle登录。 我在这里找到线程 Using Google OAuth2 with Flask

我能够移植接受的答案以使用requests-oauthlib而不是Rauth。在撰写本文时,该软件包的最后一次提交是在2019年6月,当前已被30K +存储库使用。

初始 .py

from flask import Flask
from flask_sqlalchemy import sqlAlchemy
from flask_login import LoginManager
import dir
from flask_mail import Mail

# init sqlAlchemy so we can use it later in our models
db = sqlAlchemy()
mail = Mail()

GOOGLE_LOGIN_CLIENT_ID = "myGoogle Api id .apps.googleusercontent.com" #I am sure It is correct
GOOGLE_LOGIN_CLIENT_SECRET = "my_secret_key"
def create_app():
    app = Flask(__name__)
    app.debug = True
    app.config['SECRET_KEY'] = 'secret-key-goes-here'

    # app.config['sqlALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'
    app.config['sqlALCHEMY_DATABASE_URI'] = 'sqlite:////' + str(dir.dir) + '/admin.sqlite'
    app.config['MAIL_SERVER'] = 'smtp.gmail.com'
    app.config['MAIL_PORT'] = 465
    app.config['MAIL_USERNAME'] = 'ruaxe.sdafsafsafs'
    app.config['MAIL_PASSWORD'] = 'uiykejafsaffiqklziccld'
    app.config['MAIL_USE_TLS'] = False
    app.config['MAIL_USE_SSL'] = True
    app.config['OAUTH_CREDENTIALS']  = {
        'google': {
            'id': GOOGLE_LOGIN_CLIENT_ID,'secret': GOOGLE_LOGIN_CLIENT_SECRET
        }
    }
    mail.init_app(app)
    db.init_app(app)
    with app.app_context():
        db.create_all()

    login_manager = LoginManager()
    login_manager.login_view = 'auth.login'
    login_manager.init_app(app)
    from .models import User
    @login_manager.user_loader
    def load_user(user_id):
        # since the user_id is just the primary key of our user table,use it in the query for the user
        return User.query.get(int(user_id))



    # blueprint for auth routes in our app
    from .auth import auth as auth_blueprint
    app.register_blueprint(auth_blueprint)

    # blueprint for non-auth parts of app
    from .main import main as main_blueprint
    app.register_blueprint(main_blueprint)


    return app


然后我用登录页面构建auth.py

auth = Blueprint('auth',__name__)

@auth.route('/login',methods=['GET'])
def login():
    if current_user is not None and current_user.is_authenticated:
        return redirect(url_for('main.index'))
    return render_template('login.html')

我在main.py中构建的用户查看页面

from __future__ import print_function
from flask import Blueprint,render_template,request,redirect,flash,url_for,current_app
from flask_login import login_required,current_user,login_user
from project.function import cmsHaravan as hara,cmsCalendar as cal
from .function import config as cf,cmsContacts as ct
from datetime import datetime,timedelta,date
from .models import User,Order,Shop
from . import db,mail
from flask_mail import Message
import random
import string
from werkzeug.security import generate_password_hash
import json
from requests_oauthlib import OAuth2Session
from urllib.request import urlopen

main = Blueprint('main',__name__)

class 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('main.profile',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):
    openid_url = "https://accounts.google.com/.well-kNown/openid-configuration"
    def __init__(self):
        super(GoogleSignIn,self).__init__("google")
        self.openid_config = json.load(urlopen(self.openid_url))
        self.session = OAuth2Session(
            client_id=self.consumer_id,redirect_uri=self.get_callback_url(),scope=self.openid_config["scopes_supported"]
        )

    def authorize(self):
        auth_url,_ = self.session.authorization_url(
            self.openid_config["authorization_endpoint"])
        print(auth_url)
        return redirect(auth_url)

    def callback(self):
        if "code" not in request.args:
            return None,None

        self.session.fetch_token(
            token_url=self.openid_config["token_endpoint"],code=request.args["code"],client_secret=self.consumer_secret,)

        me = self.session.get(self.openid_config["userinfo_endpoint"]).json()
        print(me)
        print(me["name"],me["email"])
        return me["name"],me["email"]
@main.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()

@main.route('/profile/<provider>')
def oauth_callback(provider):
    if not current_user.is_anonymous:
        return redirect(url_for('main.index'))
    oauth = OAuthSignIn.get_provider(provider)
    name,email = oauth.callback()
    print("da lay duoc email",email)
    if email is None:
        # I need a valid email address for my user identification
        flash('Authentication Failed.')
        return redirect(url_for('auth.login'))
    # 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 @.
        name = name
        if name is None or name == "":
            name = email.split('@')[0]

        # We can do more work here to ensure a unique nickname,if you
        # require that.
        user=User(firstname=name,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('main.index'))


@main.route('/profile')
@login_required
def profile():
    ListCarBrands = cal.getListCarBrands()
    ListProvinces = cal.getListProvinces()
    order_email = current_user.email
    list_order = {}
    i = 0
    for row in Order.query.filter_by(order_email=order_email):
        i = i + 1
        total_order = i
        list_order[i] = row.__dict__
    return render_template('profile.html',list_order=list_order,name=current_user.lastname,biensoxe=current_user.biensoxe,ListCarBrands=ListCarBrands,brands=current_user.brands,carclass=current_user.carclass,firstname=current_user.firstname,lastname=current_user.lastname,phone=current_user.phone,email=current_user.email,ListProvinces=ListProvinces,provinces=current_user.provinces)

login.html

{% extends "base.html" %}

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

    <form method="POST" action="/login">
        <div class="ui-information-body">
            <div class="align-content-center">
                {% with messages = get_flashed_messages() %}
                    {% if messages %}
                        <div class="notification is-danger">
                            {{ messages[0] }}
                        </div>
                    {% endif %}
                {% endwith %}
                <h4>Login {{ error }}</h4>
                <div class="row">
                    <div class="col-5 "><label class="label-input-group">Email </label><input type="email"
                                                                                              class="next-input"
                                                                                              name="email" id="email"
                                                                                              value=""></div>
                </div>
                <div class="row">

                    <div class="col-5 "><label class="label-input-group">Password</label><input type="password"
                                                                                                class="next-input"
                                                                                                name="password"
                                                                                                id="password"
                                                                                                value=""></div>


                </div>
                <div class="row">
                    <div class="col-5 "><span class="label-input-group"><br></span>
                        <a href="{{ url_for('main.reset_password') }}" class="btn btn-danger btn-lg btn-block">
                            Nếu bạn quên mật khẩu? Reset
                        </a></div>


                </div>
                <div class="row">
                    <div class="col-5 "><span class="label-input-group"><br></span><input
                            class="btn btn-primary btn-lg btn-block" type="submit" value="Login"></div>

                </div>

            </div>


        </div>
        </div>
    </form>
{% endblock %}

个人资料html

{% extends "base.html" %}
{% block content %}
    <form method="POST" action="/profile">
        Some code here for user can update profile
    </form>
    </div>


{% endblock %}

然后我运行程序,我可以将链接作为代码获取

    def authorize(self):
        auth_url,_ = self.session.authorization_url(
            self.openid_config["authorization_endpoint"])
        print(auth_url) ##### This function run
        return redirect(auth_url)
https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=880298757050-ij79mostsm1fccdcvuj43m0oe0quisih.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost%3A8000%2Fprofile%3Fprovider%3Dgoogle&scope=openid+email+profile&state=xwbrUEpMjhIFrM6l3PlXgcXdgzyDbd
127.0.0.1 - - [21/Aug/2020 14:03:32] "GET /authorize/google HTTP/1.1" 302 -
127.0.0.1 - - [21/Aug/2020 14:03:35] "GET /profile?provider=google&state=xwbrUEpMjhIFrM6l3PlXgcXdgzyDbd&code=4%2F3QFTG6I2FzBPUKD_Sk0hq4IUhlr0jA4EQ2fTLyQizyYsPkCLxRf_WXwQz929v4wUeJhN4IXWFWu7nLKBJ2NHhog&scope=email+profile+openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&authuser=0&prompt=consent HTTP/1.1" 302 -
127.0.0.1 - - [21/Aug/2020 14:03:35] "GET /login?next=%2Fprofile%3Fprovider%3Dgoogle%26state%3DxwbrUEpMjhIFrM6l3PlXgcXdgzyDbd%26code%3D4%252F3QFTG6I2FzBPUKD_Sk0hq4IUhlr0jA4EQ2fTLyQizyYsPkCLxRf_WXwQz929v4wUeJhN4IXWFWu7nLKBJ2NHhog%26scope%3Demail%2Bprofile%2Bopenid%2Bhttps%253A%252F%252Fwww.googleapis.com%252Fauth%252Fuserinfo.email%2Bhttps%253A%252F%252Fwww.googleapis.com%252Fauth%252Fuserinfo.profile%26authuser%3D0%26prompt%3Dconsent HTTP/1.1" 200 -
127.0.0.1 - - [21/Aug/2020 14:03:35] "GET /static/img/sign-in-with-google.png HTTP/1.1" 404 -
127.0.0.1 - - [21/Aug/2020 14:03:35] "GET /static/css/bootstrap.js HTTP/1.1" 404 -

但是我尝试将电子邮件作为路线资料中的代码打印

oauth = OAuthSignIn.get_provider(provider)
    name,email)

一无所有!所以任何人都可以帮助我 感谢所有人

解决方法

谢谢大家 我更改范围并运行!

class GoogleSignIn(OAuthSignIn):
    openid_url = "https://accounts.google.com/.well-known/openid-configuration"
    def __init__(self):
        super(GoogleSignIn,self).__init__("google")
        self.openid_config = json.load(urlopen(self.openid_url))
        self.session = OAuth2Session(
            client_id=self.consumer_id,redirect_uri=self.get_callback_url(),scope='https://www.googleapis.com/auth/userinfo.profile openid https://www.googleapis.com/auth/userinfo.email'
        )