OpenID 停用了
Flask-OpenID 是一个用于集成OpenID 2.0 认证协议的 Flask 扩展。不过,要注意,这个协议和对应的扩展库已经过时了,现代的应用都转向了基于 OAuth 2.0 的 OpenID Connect (OIDC)
csharp
# 安装
pip install Flask-OpenID
## app.py
import os
from flask import Flask, render_template, request, redirect, url_for, session, flash
from flask_openid import OpenID
# --- 1. 应用配置和初始化 ---
app = Flask(__name__)
app.secret_key = 'your-secret-key-here' # 请务必修改为一个强随机字符串
# 设置临时文件存储路径的根目录
# BASE_DIR = os.path.abspath(os.path.dirname(__file__))
# oid = OpenID(app, os.path.join(BASE_DIR, 'tmp'))
oid = OpenID(app, './tmp', safe_roots=[]) # 简化路径写法,safe_roots用于安全验证
# --- 2. 辅助函数:在请求前加载用户 ---
@app.before_request
def lookup_current_user():
"""在每个请求前,根据 session 中的 openid 加载当前用户信息"""
session.permanent = True
# 假设我们用 g 对象来存储当前用户
from flask import g
g.user = None
if 'openid' in session:
# 这里简化处理,实际应从数据库查询
# g.user = User.query.filter_by(openid=session['openid']).first()
g.user = session['openid'] # 演示用,直接将openid作为用户标识
# --- 3. 登录视图 (核心逻辑) ---
@app.route('/login', methods=['GET', 'POST'])
@oid.loginhandler # 装饰器标记为登录处理器
def login():
"""处理用户的登录请求和OpenID回调"""
# 如果用户已登录,直接重定向到下一页或主页
if g.user is not None:
return redirect(oid.get_next_url())
if request.method == 'POST':
# 获取用户在表单中输入的 OpenID 标识 URL
openid_url = request.form.get('openid')
if openid_url:
# 尝试登录,并请求获取用户的邮箱和昵称
return oid.try_login(openid_url, ask_for=['email', 'nickname'])
# GET 请求或未提供 OpenID URL 时,显示登录表单
return render_template('login.html', next=oid.get_next_url(), error=oid.fetch_error())
@oid.after_login
def create_or_login(resp):
"""OpenID 认证成功后,会回调此函数。resp 包含从 OpenID 提供者返回的用户信息"""
session['openid'] = resp.identity_url
# 从响应中提取用户信息 (如果提供并且用户授权了)
user_email = resp.email if hasattr(resp, 'email') else ''
user_nickname = resp.nickname if hasattr(resp, 'nickname') else ''
# 这里应该进行数据库操作:根据 identity_url 查找或创建用户
# 例如:
# user = User.query.filter_by(openid=resp.identity_url).first()
# if user is None:
# user = User(openid=resp.identity_url, email=user_email, nickname=user_nickname)
# db.session.add(user)
# db.session.commit()
flash('登录成功!')
# 登录成功后,跳转到登录前想访问的页面
return redirect(oid.get_next_url())
# --- 4. 登出视图 ---
@app.route('/logout')
def logout():
"""清除 session 中的用户标识,退出登录"""
session.pop('openid', None)
flash('您已成功登出。')
return redirect(url_for('login'))
# --- 5. 受保护的页面示例 ---
# 实际使用中,可以配合 Flask-Login 的 @login_required 装饰器来保护页面
@app.route('/')
def index():
if g.user is None:
return redirect(url_for('login'))
return f'Hello, {g.user}! <br> <a href="/logout">登出</a>'
# templates/login.html
<!DOCTYPE html>
<html>
<head>
<title>OpenID 登录示例</title>
</head>
<body>
<h1>OpenID 登录</h1>
<form action="" method="post">
<input type="text" name="openid" value="https://your-openid-provider.com" />
<input type="hidden" name="next" value="{{ next }}" />
<input type="submit" value="登录" />
</form>
{% if error %}
<h4>错误信息: {{ error }}</h4>
{% endif %}
</body>
</html>


csharp
浏览器 (User) 你的网站 (mysite.com) OpenID 提供者 (openid.com)
| | |
| GET / | |
|--------------------------->| |
| 302 to /login | |
|<---------------------------| |
| GET /login | |
|--------------------------->| |
| 200 (login form) | |
|<---------------------------| |
| POST /login (openid=url) | |
|--------------------------->| |
| | oid.try_login() 发现提供者地址 |
| 302 to openid.com/login | |
|<---------------------------| |
| GET /login (at openid.com) | |
|------------------------------------------------------------->|
| | (用户输入密码确认) |
|<-------------------------------------------------------------| 302 to mysite.com/login?openid_complete=...
| GET /login?openid_complete=...| |
|--------------------------->| |
| | @oid.loginhandler 检测回调 |
| | 验证签名 -> 调用 @oid.after_login|
| | 设置 session['openid'] |
| 302 to / (next) | |
|<---------------------------| |
| GET / | |
|--------------------------->| |
| 200 (Hello, user) | |
|<---------------------------| |

