如何在Python Flask网站中实现类似Reddit的Google账号登录弹窗
Flask实现Reddit风格Google账号弹窗登录方案
1. 前置准备
- 先在Google Cloud控制台创建OAuth 2.0客户端ID,授权重定向URI填写你站点的回调地址,比如
https://你的域名/auth/google/callback - 安装所需依赖:
pip install flask flask-login google-auth google-auth-oauthlib google-auth-httplib2
2. 后端Flask核心代码
from flask import Flask, redirect, request, url_for, render_template_string, session from flask_login import LoginManager, UserMixin, login_user from google.oauth2.credentials import Credentials from google_auth_oauthlib.flow import Flow from googleapiclient.discovery import build app = Flask(__name__) app.secret_key = "你的自定义加密密钥" login_manager = LoginManager() login_manager.init_app(app) # 替换为你自己的Google OAuth客户端配置 GOOGLE_CLIENT_CONFIG = { "web": { "client_id": "你的Google客户端ID", "client_secret": "你的Google客户端密钥", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "redirect_uris": ["https://你的域名/auth/google/callback"] } } SCOPES = ["openid", "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile"] # 简易用户模型,可替换为你自己的数据库模型 class User(UserMixin): def __init__(self, user_id, email, name): self.id = user_id self.email = email self.name = name # 可自行补充从数据库查询/创建用户的静态方法 @login_manager.user_loader def load_user(user_id): # 这里替换为从数据库查询用户的逻辑 return User(user_id, "test@example.com", "测试用户") # Google登录入口 @app.route("/auth/google") def google_login(): flow = Flow.from_client_config(GOOGLE_CLIENT_CONFIG, scopes=SCOPES) flow.redirect_uri = url_for("google_callback", _external=True) authorization_url, state = flow.authorization_url(access_type="offline", include_granted_scopes="true") # 把state存入session用于后续校验 session["state"] = state return redirect(authorization_url) # Google登录回调 @app.route("/auth/google/callback") def google_callback(): state = session.get("state") flow = Flow.from_client_config(GOOGLE_CLIENT_CONFIG, scopes=SCOPES, state=state) flow.redirect_uri = url_for("google_callback", _external=True) flow.fetch_token(authorization_response=request.url) # 获取用户信息 credentials = flow.credentials user_info_service = build("oauth2", "v2", credentials=credentials) user_info = user_info_service.userinfo().get().execute() # 这里写你自己的用户处理逻辑:判断用户是否存在,不存在则创建,然后登录 user = User(user_id=user_info["id"], email=user_info["email"], name=user_info["name"]) login_user(user) # 返回关闭弹窗+父页面刷新的脚本,实现Reddit同款弹窗关闭效果 return """ <script> window.opener.location.reload(); window.close(); </script> """ # 首页,包含登录按钮 @app.route("/") def index(): return render_template_string(""" <!-- 登录按钮样式参考Reddit设计 --> <button id="google-login-btn" style="padding: 10px 20px; border: 1px solid #dadce0; border-radius: 20px; background: white; cursor: pointer; display: flex; align-items: center; gap: 10px;"> <svg width="18" height="18" viewBox="0 0 18 18"> <!-- 这里填入Google logo的svg路径 --> </svg> 使用Google账号登录 </button> <script> document.getElementById("google-login-btn").addEventListener("click", () => { // 弹窗参数和Reddit保持一致:固定宽高,居中显示 const width = 500; const height = 600; const left = (window.screen.width / 2) - (width / 2); const top = (window.screen.height / 2) - (height / 2); window.open( "/auth/google", "google_login", `width=${width},height=${height},top=${top},left=${left},resizable=yes,scrollbars=yes` ); }); </script> """) if __name__ == "__main__": app.run(debug=True)
3. 注意事项
- 生产环境不要硬编码客户端密钥、加密密钥等敏感信息,建议通过环境变量读取
- 必须校验回调请求的state参数,防止CSRF攻击
- 生产环境站点必须使用HTTPS,Google OAuth不允许HTTP地址作为回调地址(本地调试除外)
- 可以自行调整按钮的样式、弹窗的宽高参数,和Reddit的登录效果完全对齐
内容的提问来源于stack exchange,提问作者Nikhil Tank
相关产品推荐
相关产品推荐

