Link Search Menu Expand Document

Python Flask快速与OneAuth集成

  1. 准备工作
  2. 安装依赖
  3. 创建一个 Flask 应用
  4. 创建 OneAuth 开发者账户
  5. 连接应用到 OneAuth
  6. 配置并保护相关 URI
  7. 总结
  8. 参考

本教程将介绍如何使用 OneAuth 的统一身份验证服务,它能让我们在 Python 项目中轻松处理用户数据。

本节介绍如何使用Python Flask快速与OneAuth集成,将OneAuth作为WEB应用程序的用户存储库并实现用户登录。

准备工作

本教程使用了 Python3.x 版本构建程序,所以请留意各项依赖包的版本。

  • Flask
  • Flask-OIDC
  • OneAuth SDK
  • 一个免费的 OneAuth 账户
  • 已有或新建的Web应用程序或项目,或可使用本教程代码示例 Oneauth Python Example,基于MIT协议,可以免费/商业使用。

安装依赖

首先我们使用 venv 创建一个干净的开发环境,并激活该环境

python3 -m venv flaskOneAuth
source ./flaskOneAuth/bin/activate

接下来利用 pip 安装所需的依赖

pip install flask>=2.0.2 flask-oidc>=1.4.0

安装成功后,我们安装了所需的 Flask 和 OneAuth 依赖项,让我们开始构建 Flask 应用

创建一个 Flask 应用

我们创建一个名字为 flaskapp 的项目目录,然后创建一个名为 app.py 的文件,包含下面的代码

# imports for Flask
from flask import Flask, Response

app = Flask(__name__)

@app.route("/protectme")
def protect_me():
    return Response("I should be protected!")

@app.route("/")
def landing_page():
    return Response("I am open for any visitors")

接下来我们可以使用以下命令运行这个 Flask 应用程序

set FLASK_APP=app.py
flask run

在 Web 浏览器中访问 http://localhost:5000,您应该看到

image

现在转到 http://localhost:5000/protectme 看看。这个页面应该需要身份验证才能访问,但现在它似乎没有任何保护

image

但可以确定的是,我们的基础应用已启动并运行,下面让我们为它增加身份验证功能

创建 OneAuth 开发者账户

访问打开注册页面

输入表单信息后提交,会提示输入验证码,以确保你没有输错Email地址。此时需要查收你的Email,找到类似的邮件

image

然后继续输入你接受到的验证码后,会提示创建成功,再回到你的邮箱,查看用户激活邮件

image

点击激活,会提示设置管理员密码。设置好之后,用你的Email登录。会看到管理员面板

image

可以看到浏览器地址栏标记黄色的部分,就是你的租户地址了,不仅仅可以通过这个地址访问到管理面板,而且后续我们会用到这个地址配置协议参数。

连接应用到 OneAuth

我们接下来要在 OneAuth 上创建一个应用。我们选择左侧菜单的【应用】然后在面板右侧点击【创建应用】

我们会看到创建应用的弹出框:

image

我们在这里认证方式选择 OIDC,应用类型选择 Web 应用,点击下一步:

image

我们创建一个应用名为 flaskapp 的应用,将 http://localhost:5000/oidc/callback 作为登录重定向的地址。

接下来,我们会看到创建好的应用信息(请留意黄色标记部分):

image

⚠️特别步骤:我们需要增加一个安全域,CORS防止调试时被浏览器拦截,点击左侧菜单【API】选择【安全域】

然后点击右侧的【添加域】根据下面的图示输入:

image

配置并保护相关 URI

很好,到此我们已经获取到了必要的参数了。接下来我们创建一份 OIDC 客户端配置,创建文件 openidconnect_secrets.json 输入:

{
  "web": {
    "client_id": "",
    "client_secret": "",
    "auth_uri": "/oauth/v1/authorize",
    "token_uri": "/oauth/v1/token",
    "issuer": "/oauth/v1",
    "userinfo_uri": "/oauth/v1/userinfo",
    "redirect_uris": [
      "http://localhost:5000/oidc/callback"
    ]
  }
}

需要将双括号的变量替换为已经获取到的参数,完整如下:

{
  "web": {
    "client_id": "7Bluj051DFz63z6E0258p3h8dv9Kzva4",
    "client_secret": "Dt934T3427EwzvGd3Z2gJ5o14D0061mRF66i1F9T435G85aA",
    "auth_uri": "https://yourdomain.oneauth.cn/oauth/v1/authorize",
    "token_uri": "https://yourdomain.oneauth.cn/oauth/v1/token",
    "issuer": "https://yourdomain.oneauth.cn/oauth/v1",
    "userinfo_uri": "https://yourdomain.oneauth.cn/oauth/v1/userinfo",
    "redirect_uris": [
      "http://localhost:5000/oidc/callback"
    ]
  }
}

⚠️请注意:实际使用过程中 URL 值与本文例子是不同的,需多加留意。

我们增加一些代码,读取配置:

# imports for Flask
from flask import Flask, Response

from os import environ
from flask_oidc import OpenIDConnect

app = Flask(__name__)

# secret credentials for OneAuth connection
app.config["OIDC_CLIENT_SECRETS"] = "openidconnect_secrets.json"
app.config["OIDC_COOKIE_SECURE"] = False
app.config["OIDC_CALLBACK_ROUTE"] = "/oidc/callback"
app.config["OIDC_SCOPES"] = ["openid", "email", "profile"]
app.config["SECRET_KEY"] = environ.get("SECRET_KEY")
app.config["OIDC_ID_TOKEN_COOKIE_NAME"] = "oidc_token"
# instantiate OpenID client to handle user session
oidc = OpenIDConnect(app)
# client will determine if a user has an appropriate account
oneauth_client = Client(environ.get("ONEAUTH_TENANT_URL"),
                          environ.get("ONEAUTH_AUTH_TOKEN"))

@app.route("/protectme")
def protect_me():
    return Response("I should be protected!")

@app.route("/")
def landing_page():
    return Response("I am open for any visitors")

我们新增加了4、5行以引入依赖的包。第10行至20行,我们将 openidconnect_secrets.json 的配置引入到 Flask应用中。新代码的其余部分设置 Flask 应用的配置值,可用于实例化 OpenID Connect。

到此,我们的基础设置已经搞定了,但保护相关的资源还需要我们添加代码声明一下:

# imports for Flask
from flask import Flask, Response
from flask import redirect, g, url_for
from os import environ
from flask_oidc import OpenIDConnect

app = Flask(__name__)

# 连结到 OneAuth 服务的Flask参数设置
app.config["OIDC_CLIENT_SECRETS"] = "openidconnect_secrets.json"
# 必须在生产环境中将此设置为 True
app.config["OIDC_COOKIE_SECURE"] = False
# Web应用中用于处理用户登录的 URL
app.config["OIDC_CALLBACK_ROUTE"] = "/oidc/callback"
# 用户登录时要请求的有关用户的数据,此处我们要求提供基本的电子邮件、姓名和个人资料信息
app.config["OIDC_SCOPES"] = ["openid", "email", "profile"]
# 这是一个 Flask 设置,用于确保会话安全,绝不能公开它
app.config["SECRET_KEY"] = environ.get("SECRET_KEY")
app.config["OIDC_ID_TOKEN_COOKIE_NAME"] = "oidc_token"

oidc = OpenIDConnect(app)


@app.before_request
def before_request():
    """实现检查用户是否在每次请求之前登录过"""
    if oidc.user_loggedin:
        g.user = oidc.user_getfield("sub")
    else:
        g.user = None

@app.route("/protectme")
@oidc.require_login
def protect_me():
    return Response("I should be protected!")

@app.route("/")
def landing_page():
    return Response("I am open for any visitors")

@app.route("/login")
@oidc.require_login
def login():
    return redirect(url_for(".protectme"))

@app.route("/logout")
def logout():
    oidc.logout()
    return redirect(url_for(".landing_page"))

我们又在第二行添加了 Flask 相关方法,以完成我们的保护功能。24行-30行,实现检查用户是否在每次请求之前登录过。

如果路由由于 @oidc.require_login 装饰器而需要登录用户,则用户将被重定向到登录页面。我们还在 /login 和 /logout 下添加了路由,使登录和退出我们的应用成为可能。

在命令行运行下面的指令,设置环境变量:

# this tells Flask we want to run the built-in server in dev mode
export FLASK_ENV=development
# make sure to use a very long random string here that cannot be guessed
export SECRET_KEY='a very long string with lots of numbers and letters'

然后在这个命令行终端中重新运行我们的 Flask 应用:

set FLASK_APP=app.py
flask run

运行起来后,当我们尝试通过访问 http://localhost:5000/protectme 转到 /protectme 路由时,让我们测试重定向功能,此时我们应被重定向到 OneAuth 登录页面:

image

输入你的 OneAuth 开发者用户名和密码以登录你的 Flask 应用。一切顺利的话,你会看到跳转到路由后显示的信息:

image

到此,对接成功了!

之后当你输入 http://localhost:5000/logout 时会取消对你的用户的身份验证,此时再次访问 /protectme 又会跳转到认证的界面重新认证。

⚠️请注意:出于开发目的,这仅适用于测试。但在生产应用程序中,你需要创建其他帐户供用户登录。

总结

我们通过 Flask 构建了一个简单的应用,利用Open ID Connect 协议并对接 OneAuth 提供的身份服务,实现了保护我们特定路由的方法。

参考

Flask-OIDC 文档