准备用于身份验证的 Python Flask Web 应用

本教程是一个系列教程的第 2 部分,演示如何生成 Python Flask Web 应用,并使用 Microsoft 标识平台添加登录支持。 在本系列教程的第 1 部分中,你在 Microsoft Entra ID 租户中注册和配置了应用程序。

在本教程中,你将了解:

  • 创建新的 Python Flask Web 应用项目
  • 安装应用依赖项
  • 添加应用程序的 UI 组件
  • 将 Flask Web 应用配置为使用 Microsoft Entra ID 进行身份验证

先决条件

创建新的 Python Web 应用项目

若要完成本教程的其余部分,需要创建 Python Flask Web 应用项目。 如果希望使用已完成的代码示例进行学习,请从 GitHub 下载 Python Flask Web 应用示例

若要从头开始构建 Python Flask Web 应用,请执行以下步骤:

  1. 创建一个文件夹来托管应用程序,并将其命名为 flask-web-app
  2. 导航到项目目录并创建三个名为 app.py、app.config.py 和 requirements.txt 的文件
  3. 在项目的根文件夹中创建 .env 文件。
  4. 在项目根目录中创建名为 templates 的文件夹。 Flask 查找此子目录中的呈现模板。

创建文件后,项目的文件和目录应类似于以下结构:

python-webapp/
├── templates/
│     ├── display.html
│     ├── index.html
│     ├── login.html
├── .env.sample
├── app.py
├── app.config.py
│── requirements.txt

安装应用依赖项

构建的守护程序应用使用 identity,即适用于 Python 的 Microsoft 身份验证库 (MSAL) 周围的包装器。 还需安装 Flask、Flask 会话、请求以及应用需要的所有其他依赖项。 使用这些依赖项更新“requirements.txt”。

Flask>=2.2
Flask-Session>=0.3.2,<0.6
werkzeug>=2
requests>=2,<3
identity>=0.5.1,<0.6
python-dotenv<0.22 

添加应用程序 UI 组件

在本部分中,将为应用中定义的每个路由创建 HTML 模板,包括登录、注销、API 调用和错误模板。 按照以下步骤为每个页面创建模板:

登录模板

在 templates 文件夹中,创建一个名为 login.html 的 HTML 文件,并添加以下内容

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Microsoft Identity Python Web App: Login</title>
</head>
<body>
    <h1>Microsoft Identity Python Web App</h1>

    {% if user_code %}
    <ol>
      <li>To sign in, type <b>{{ user_code }}</b> into
        <a href='{{ auth_uri }}' target=_blank>{{ auth_uri }}</a>
        to authenticate.
      </li>
      <li>And then <a href="{{ url_for('auth_response') }}">proceed</a>.</li>
    </ol>
    {% else %}
    <ul><li><a href='{{ auth_uri }}'>Sign In</a></li></ul>
    {% endif %}

    <hr>
    <footer style="text-align: right">Microsoft identity platform Web App Sample {{ version }}</footer>
</body>
</html>

此模板表示用户可以登录到应用程序的登录页。

索引模板

在 templates 文件夹中,创建一个名为 index.html 的 HTML 文件,并添加以下内容

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Microsoft Identity Python Web App: Index</title>
</head>
<body>
    <h1>Microsoft Identity Python Web App</h1>
    <h2>Welcome {{ user.get("name") }}!</h2>

    <ul>
    {% if config.get("ENDPOINT") %}
      <li><a href='/call_downstream_api'>Call a downstream API</a></li>
    {% endif %}

    <li><a href="/logout">Logout</a></li>
    </ul>

    <hr>
    <footer style="text-align: right">Microsoft identity platform Web App Sample {{ version }}</footer>
</body>
</html>

索引模板充当 Web 应用的主页,在用户访问应用的根 URL 时呈现。

“显示”页面

此模板用于显示下游 API 调用的结果。 将以下代码片段添加到 display.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Microsoft Identity Python Web App: API</title>
</head>
<body>
    <a href="javascript:window.history.go(-1)">Back</a> <!-- Displayed on top of a potentially large JSON response, so it will remain visible -->
    <h1>Result of the downstream API Call</h1>
    <pre>{{ result |tojson(indent=4) }}</pre> <!-- Just a generic json viewer -->
</body>
</html>

错误模板

身份验证错误模板

在 templates 文件夹中,创建一个名为 auth_error.html 的 HTML 文件,该文件显示可能出现的任何错误消息。 将以下代码添加到 auth_error.html

<!DOCTYPE html>*
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Microsoft Identity Python Web App: Error</title>
</head>
<body>
    <h2>Login Failure</h2>
    <dl>
      {#
        Flask automatically escapes these unsafe input, so we do not have to.
        See also https://flask.palletsprojects.com/en/2.0.x/templating/#jinja-setup
      #}
      <dt>{{ result.get("error") }}</dt>
      <dd>{{ result.get("error_description") }}</dd>
    </dl>
    <hr>
    <a href="{{ url_for('index') }}">Homepage</a>
</body>
</html>

配置错误模板

在 templates 文件夹中,创建一个名为 config_error.html 的 HTML 文件,该文件显示所需配置缺失时的消息。 将以下代码添加到 config_error.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Microsoft Identity Python Web App: Error</title>
</head>
<body>
    <h2>Config Missing</h2>
    <p>
        Almost there. Did you forget to set up
<a target=_blank
href="https://learn.microsoft.com/azure/active-directory/develop/web-app-quickstart?pivots=devlang-python#step-5-configure-the-sample-app">
necessary environment variables</a> for your deployment?
    </p>
    <hr>
    <a href="{{ url_for('index') }}">Homepage</a>
</body>
</html>

创建 配置文件

在代码编辑器中,打开保存配置参数的 app_config.py,并添加以下代码

import os
AUTHORITY= os.getenv("AUTHORITY")

# Application (client) ID of app registration
CLIENT_ID = os.getenv("CLIENT_ID")
# Application's generated client secret: never check this into source control!
CLIENT_SECRET = os.getenv("CLIENT_SECRET")
 
REDIRECT_PATH = "/getAToken"  # Used for forming an absolute URL to your redirect URI.

ENDPOINT = 'https://graph.microsoft.com/v1.0/me'  
SCOPE = ["User.Read"]

# Tells the Flask-session extension to store sessions in the filesystem
SESSION_TYPE = "filesystem"

创建 .env 文件以存储配置设置。

在此示例中,你将使用 .env 文件来存储和管理不应嵌入到代码中的应用程序配置设置、环境变量和凭据。 打开在项目目录的根目录中创建的 .env 文件,然后添加以下值。

# The following variables are required for the app to run.
CLIENT_ID=<client id>
CLIENT_SECRET=<client secret>
AUTHORITY=<Enter_your_authority_url>

在 .env.sample 文件中替换以下占位符

    • CLIENT_ID 替换为应用注册概述页上提供的“应用程序(客户端) ID”
    • CLIENT_SECRET 替换为在“证书和机密”中创建的客户端机密
    • AUTHORITY将 替换为 https://login.microsoftonline.com/<TENANT_GUID>。 应用注册概述页上提供了“目录(租户) ID”

下一步

了解如何向 Python Flask Web 应用添加登录支持(本系列教程的下一部分):