expr

Python Flask 与OneAuth IDaaS快速集成身份验证

用户身份验证是 Web 应用程序中的一项基本功能,因此人们可以创建和访问自己的帐户,但不幸的是,身份验证并不总是很容易设置,可能经常错误地实现登录和注销功能。本教程将介绍如何使用 OneAuth 的统一身份验证服务,对多达 1,000 个活动用户帐户免费使用,它能让我们在 Flask 应用中轻松处理用户数据。

主要步骤:

  • 准备工作
  • 安装依赖
  • 创建一个Flask应用
  • 创建OneAuth开发者账户
  • 连接应用到OneAuth
  • 配置并保护相关uri

准备工作

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

  • Flask
  • Flask-OIDC
  • OneAuth SDK
  • 一个免费的 OneAuth 账户

本教程代码将放置在 Github 仓库,基于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,您应该看到

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

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

创建 OneAuth 开发者账户

访问打开注册页面

 

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

 

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

 

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

 

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

连接应用到 OneAuth

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

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

 

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

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

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

 

 

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

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

 

配置并保护相关 URI

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

{
  "web": {
    "client_id": "{{ ONEAUTH_APP_CLIENT_ID }}",
    "client_secret": "{{ ONEAUTH_APP_CLIENT_SECRET }}",
    "auth_uri": "{{ ONEAUTH_TENANT_URL }}/oauth/v1/authorize",
    "token_uri": "{{ ONEAUTH_TENANT_URL }}/oauth/v1/token",
    "issuer": "{{ ONEAUTH_TENANT_URL }}/oauth/v1",
    "userinfo_uri": "{{ ONEAUTH_TENANT_URL }}/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 登录页面:

 

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

 

我们对接成功了!

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

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

总结

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

参考

Flask-OIDC 文档

OneAuth 开发者指南

转载请注明,谢谢