将Google身份验证与Python和Dash集成

将Google身份验证与Python和Dash集成,python,authentication,flask,plotly-dash,google-authentication,Python,Authentication,Flask,Plotly Dash,Google Authentication,我希望将谷歌认证整合到Dash应用程序中。我发现了一篇非常有用的关于如何使用的帖子,随后我设置了GoogleAPI访问,并显示了身份验证屏幕,允许用户使用他们的Google帐户登录。处理作为回报的代币是我迷路的地方。我不清楚如何访问它们或在进一步的回调中正确使用它们来验证用户并登录 最后,在允许访问之前,我需要根据单独的数据库检查已验证的电子邮件。管道的这一端正在工作,我只是错过了谷歌的这篇认证文章。 下面是我试图做的一个简单的例子。如果你有你的电脑,它会工作的 面对类似的情况,我最终使用了一个

我希望将谷歌认证整合到Dash应用程序中。我发现了一篇非常有用的关于如何使用的帖子,随后我设置了GoogleAPI访问,并显示了身份验证屏幕,允许用户使用他们的Google帐户登录。处理作为回报的代币是我迷路的地方。我不清楚如何访问它们或在进一步的回调中正确使用它们来验证用户并登录

最后,在允许访问之前,我需要根据单独的数据库检查已验证的电子邮件。管道的这一端正在工作,我只是错过了谷歌的这篇认证文章。 下面是我试图做的一个简单的例子。如果你有你的电脑,它会工作的


面对类似的情况,我最终使用了一个修改版的

虽然库允许通过
flask.request.cookies.get('AUTH-user')
访问用户名,但鉴于需要获取用户的电子邮件ID(由谷歌验证),您可以对库的
Google\u AUTH.py
文件进行以下更改:

。。。
COOKIE\u AUTH\u USER\u EMAIL='AUTH-USER-EMAIL'
...
类GoogleAuth(认证):
...
def登录_回调(自):
...
google=self.\uuuu获取\uGoogle\uAuth(令牌=token)
resp=google.get(os.environ.get('google\u AUTH\u USER\u INFO\u URL'))
如果响应状态\ U代码==200:
user_data=resp.json()
r=flask.redirect(flask.session['redirect_URL']))
r、 设置cookie(cookie认证用户名称,用户数据['NAME'],最大年龄=cookie到期日)
#在cookie中存储(Google)已验证用户的电子邮件ID
r、 设置cookie(cookie验证用户电子邮件,用户数据['EMAIL'],最大年龄=cookie过期)
r、 设置cookie(cookie认证访问令牌,令牌['ACCESS\u TOKEN'],最大年龄=cookie到期)
session[user_data['name']=token['access_token']
返回r
...
...
@静力学方法
def注销():
r=烧瓶。重定向(“/”)
r、 删除\u cookie(cookie\u验证\u用户名)
#不要忘记删除自定义cookie
r、 删除cookie(cookie认证用户电子邮件)
r、 删除\u cookie(cookie\u授权\u访问\u令牌)
返回r
。。。然后通过
flask.request.cookies.get('AUTH-user-email')
(或为
COOKIE\u AUTH\u user\u email设置的任何值)访问(谷歌)已验证用户的电子邮件ID

或者,如果您不希望将用户的详细信息(姓名、电子邮件等)存储在cookie中,您可以/可以在允许用户访问之前在上面的部分中进行更改,以对照您的数据库检查用户的电子邮件ID,而不是在
破折号
应用程序的代码中进行更改

import dash
from dash.dependencies import Input, Output, State
import dash_bootstrap_components as dbc
import dash_html_components as html
import dash_core_components as dcc
from flask import redirect, request
from flask_login import logout_user, current_user, LoginManager
import requests
import json
from oauthlib.oauth2 import WebApplicationClient
from flask_login import UserMixin
from sqlalchemy import (Table, 
    create_engine, 
    MetaData, 
    String,
    Integer, 
    DateTime, 
    Column)
from sqlalchemy.ext.declarative import declarative_base

import auth_utils

app = dash.Dash(__name__)

server = app.server

# Setup the login manager for the server
login_manager = LoginManager()
login_manager.init_app(server)
login_manager.login_view = '/login'

# Set up User class for login manager
Base = declarative_base()

class User(Base, UserMixin):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True)
    name = Column(String)
    email = Column(String, unique=True)

@login_manager.user_loader
def load_user(user_id):
    return User.get(user_id)

# Get secret keys
GOOGLE_CLIENT_ID = 'your-keys-here'
GOOGLE_CLIENT_SECRET = 'and-here'
client = WebApplicationClient(GOOGLE_CLIENT_ID)

GOOGLE_DISCOVERY_URL = "https://accounts.google.com/.well-known/openid-configuration"

app.layout = html.Div([
    dcc.Location(id='base-url'),
    dcc.Location(id='login-url', refresh=True, pathname='/login'),
    html.Div(id='hidden-google-redirect-uri',
        style={'display': 'none'}),
    html.Button('Login with Google',
        id='google-login-button',
        n_clicks=0),
    html.Div(id='login-success-display')
])

@app.callback(
    Output('hidden-google-redirect-uri', 'children'),
    Input('google-login-button', 'n_clicks'),
)
def google_login(n_clicks):
    if n_clicks > 0:
        google_provider_cfg = requests.get(GOOGLE_DISCOVERY_URL).json()
        google_auth_endpoint = google_provider_cfg["authorization_endpoint"]

        request_uri = client.prepare_request_uri(
            google_auth_endpoint,
            redirect_uri=request.base_url + "/callback",
            scope=["openid", "email", "profile"]
        )
        return dcc.Location(href=request_uri, id='_hidden-google-redirect-uri')
    
    else:
        return html.Div()

@app.callback(
    Output('login-success-display', 'children'),
    Input('google-login-button', 'n_clicks'),
    State('hidden-google-redirect-uri', 'children')
)
def google_response(n_clicks, google_response):
    if n_clicks == 0:
        return html.H3('Not logged in.')
    # Get authorization code Google sent back to you
    code = request.args.get("code")

    # Find out what URL to hit to get tokens that allow you to ask for
    # things on behalf of a user
    google_provider_cfg = requests.get(GOOGLE_DISCOVERY_URL).json()
    token_endpoint = google_provider_cfg["token_endpoint"]

    # Prepare and send a request to get tokens
    token_url, headers, body = client.prepare_token_request(
        token_endpoint,
        authorization_response=request.url,
        redirect_url=request.base_url,
        code=code
    )
    token_response = requests.post(
        token_url,
        headers=headers,
        data=body,
        auth=(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET),
    )

    client.parse_request_body_response(json.dumps(token_response.json()))
    userinfo_endpoint = google_provider_cfg["userinfo_endpoint"]
    uri, headers, body = client.add_token(userinfo_endpoint)
    userinfo_response = requests.get(uri, headers=headers, data=body)

    if userinfo_response.json().get("email_verified"):
        unique_id = userinfo_response.json()["sub"]
        user_email = userinfo_response.json()["email"]
        user_name = userinfo_response.json()["given_name"]
        return html.H3('User verified via Google.')
    else:
        return html.H3('User email not available or not verified by Google.')

if __name__ == "__main__":
    app.run_server(port=8800, debug=True)