Flask》》 Flask-OpenID 认证、 OpenID Connect (OIDC)

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)          |                                 |
    |<---------------------------|                                 |
相关推荐
掘金码甲哥2 小时前
这篇优雅安装k8s集群的姿势,请务必投喂给AI智能体, 包装包活的那种!
后端
m0_734949792 小时前
怎么利用Navicat进行调整备份文件压缩等级_详细配置与操作步骤
jvm·数据库·python
m0_741173333 小时前
如何处理SQL中的NULL值_使用ISNULL或COALESCE函数
jvm·数据库·python
AC赳赳老秦3 小时前
OpenClaw进阶技巧:批量修改文件内容、替换关键词,解放双手
java·linux·人工智能·python·算法·测试用例·openclaw
步辞3 小时前
css伪类选择器-nth-child应用技巧_循环选择列表或表格行的实现方法
jvm·数据库·python
IT_陈寒3 小时前
Vue的v-for里用index当key,我被自己坑惨了
前端·人工智能·后端
invicinble4 小时前
Spring如何把bean注册到容器里
java·后端·spring
xcbrand4 小时前
快消品品牌策划公司哪家好
大数据·人工智能·python
阿丰资源4 小时前
基于SpringBoot+MySQL的网上订餐系统(附源码)
spring boot·后端·mysql