首页 > 编程问答 >如何获取部署在 Azure 应用服务上并通过 Microsoft 身份提供商进行身份验证的 Python Web 应用程序中的用户详细信息?

如何获取部署在 Azure 应用服务上并通过 Microsoft 身份提供商进行身份验证的 Python Web 应用程序中的用户详细信息?

时间:2024-08-05 15:50:28浏览次数:9  
标签:python azure plotly-dash azure-appservice azure-authentication

我使用 Python Dash 包构建了一个 Web 应用程序,并将该应用程序部署在 Azure 应用服务上。 Web 应用程序当前通过 Azure 门户的应用程序服务使用 Microsoft 身份提供程序进行身份验证。但是如何获取登录用户的详细信息呢?在本地运行时如何验证我的 Web 应用程序?

我当前的登录流程也是自动重定向,因此没有登录页面,也没有注销按钮/选项。

我希望获得登录用户详细信息这就是我到目前为止所实现的:

authentication.py

import msal
import requests

authority = 'https://login.microsoftonline.com/<tenant-id>'
scope = ["https://graph.microsoft.com/.default"]
client_id = <client-id>
client_secret = <client-secret>


def authentication():
    app = msal.ConfidentialClientApplication(
        client_id,
        authority=authority,
        client_credential=client_secret
    )

    token_response = app.acquire_token_for_client(scopes=scope)
    access_token = token_response['access_token']

    headers = {
        'Authorization': f'Bearer {access_token}'
    }

    response = requests.get(
        'https://graph.microsoft.com/v1.0/me', headers=headers)
    user_data = response.json()

    print("~~~~~~~~~~~~~~~~~~~~~~")
    for key, value in user_data.items():
        print(f'{key}: {value}')
    print("~~~~~~~~~~~~~~~~~~~~~~")

    return

这是我的 app.py 我调用身份验证函数的地方:

from functions.app import authentication
# other imports ...

stylesheets = [
    "https://unpkg.com/@mantine/dates@7/styles.css",
    "https://unpkg.com/@mantine/code-highlight@7/styles.css",
    "https://unpkg.com/@mantine/charts@7/styles.css",
    "https://unpkg.com/@mantine/carousel@7/styles.css",
    "https://unpkg.com/@mantine/notifications@7/styles.css",
    "https://unpkg.com/@mantine/nprogress@7/styles.css",
]

app = Dash(__name__, use_pages=True, external_stylesheets=stylesheets)

server = app.server

authentication.authentication()

app.layout = dmc.MantineProvider(
    ... # layout stuff
)

if __name__ == '__main__':
    app.run_server(debug=True, port=8000)

但这就是我得到的我运行我的 python dash Web 应用程序(python ./app.py):

{'error': {'code': 'BadRequest', 'message': '/me request is only valid with delegated authentication flow.', 'innerError': {'date': '2024-08-05T03:46:12', 'request-id': '<request-id>', 'client-request-id': '<client-request-id>'}}}

当前的代码使用的是客户端凭据流来获取令牌,此方法适用于应用程序本身需要访问资源而不是用户的场景。为了获取登录用户的详细信息,需要使用授权码流或身份验证代码流,该流涉及获取用户同意以访问他们的数据。

以下是使用 MSAL for Python 获取 Azure 应用服务中 Python Dash 应用的登录用户详细信息的步骤:

1. 更新 Azure 应用注册

  • 在 Azure 门户中导航到的应用程序注册。
  • 在“管理”下,转到“身份验证”。
  • 在“平台配置”下,选择“添加平台”。
  • 选择“Web”。
  • 在“重定向 URI”下,添加的 Web 应用程序的重定向 URI(例如, https://your-app-name.azurewebsites.net/.auth/login/aad/callback )。这应该与在 Azure 应用服务的身份验证设置中配置的重定向 URI 相匹配。
  • 在“隐式授权”下,选中“ID 令牌”。这是必需的,以便在客户端应用程序中获取令牌。
  • 保存的更改。

2. 安装 Flask 库

pip install Flask

3. 更新的 Python 代码

import msal
import requests
from flask import Flask, render_template, session, redirect, url_for, request
import os

app = Flask(__name__)
app.secret_key = os.urandom(24) # 重要提示:出于安全考虑,请使用随机生成的密钥

authority = 'https://login.microsoftonline.com/<tenant-id>'
client_id = '<client-id>'
client_secret = '<client-secret>' # 仅适用于机密客户端应用程序
scope = ["User.Read"] # 请求用户配置文件权限
redirect_uri = 'https://your-app-name.azurewebsites.net/.auth/login/aad/callback' # 更新为的重定向 URI

# 创建 MSAL 机密客户端应用程序
msal_app = msal.ConfidentialClientApplication(
    client_id,
    authority=authority,
    client_credential=client_secret, # 如果是机密客户端应用程序,则取消注释此行
    # 如果是公共客户端应用程序,请使用以下内容:
    # redirect_uri=redirect_uri,
)

@app.route("/")
def index():
    if not session.get("user"):
        return redirect(url_for("login"))
    return render_template('index.html', user=session['user'])

@app.route("/login")
def login():
    session["state"] = str(os.urandom(24)) # 防止 CSRF 攻击
    auth_url = msal_app.get_authorization_request_url(
        scopes=scope,
        state=session["state"],
        redirect_uri=redirect_uri,
    )
    return redirect(auth_url)

@app.route('.auth/login/aad/callback')
def authorized():
    if request.args.get('state') != session.get("state"):
        return redirect(url_for("index"))  # No-OP. Don't log in if state doesn't match
    if "error" in request.args:  # Authentication/Authorization failure
        return render_template("auth_error.html", result=request.args)
    if request.args.get('code'):
        cache = msal.SerializableTokenCache()
        result = msal_app.acquire_token_by_authorization_code(
            request.args['code'],
            scopes=scope,  # Misspelled scope would cause an HTTP 400 error here
            redirect_uri=redirect_uri,
            token_cache=cache,
        )
        if "error" in result:
            return render_template("auth_error.html", result=result)
        session["user"] = result.get("id_token_claims")
        session["token_cache"] = cache.serialize()
    return redirect(url_for("index"))

@app.route("/logout")
def logout():
    session.clear()  # This helps prevent CSRF attacks
    return redirect(
        authority + "/oauth2/v2.0/logout" +
        "?post_logout_redirect_uri=" + url_for("index", _external=True)
    )

# 此方法从缓存或使用刷新令牌获取令牌
def _get_token_from_cache(scope=None):
    cache = msal.SerializableTokenCache()
    if session.get("token_cache"):
        cache.deserialize(session["token_cache"])
    account = msal_app.get_accounts()
    if account:
        # 尝试从缓存中获取令牌
        token_response = msal_app.acquire_token_silent(
            scope, account=account, token_cache=cache
        )
        if token_response:
            session["token_cache"] = cache.serialize()
            return token_response

@app.route('/graph-call')
def graphcall():
    token = _get_token_from_cache(scope=["User.Read"])
    if not token:
        return redirect(url_for("login"))
    graph_data = requests.get(  # Use token to call downstream service
        'https://graph.microsoft.com/v1.0/me',
        headers={'Authorization': 'Bearer ' + token['access_token']},
    ).json()
    return render_template('display.html', result=graph_data)

if __name__ == "__main__":
    app.run()

4. 创建模板文件(templates/index.html、templates/display.html、templates/auth_error.html)

templates/index.html

<!DOCTYPE html>
<html>
<head>
    <title>MS 身份验证示例</title>
</head>
<body>
    {% if user %}
        <h1>欢迎,{{ user.name }}!</h1>
        <a href="/graph-call">调用 Microsoft Graph</a>
        <br>
        <a href="/logout">登出</a>
    {% else %}
        <a href="/login">登录</a>
    {% endif %}
</body>
</html>

templates/display.html

<!DOCTYPE html>
<html>
<head>
    <title>MS Graph API 调用结果</title>
</head>
<body>
    <h1>Microsoft Graph API 调用结果</h1>
    <pre>{{ result }}</pre>
</body>
</html>

templates/auth_error.html

<!DOCTYPE html>
<html>
<head>
    <title>身份验证错误</title>
</head>
<body>
    <h1>身份验证错误</h1>
    <p>{{ result }}</p>
</body>
</html>

说明:

  1. 配置: 使用的应用程序注册值替换 <tenant-id> <client-id> <client-secret> <redirect-uri>
  2. 登录和重定向: 用户访问的应用程序时, /login 路由会使用 MSAL 库生成登录 URL 并将用户重定向到 Microsoft 身份验证。身份验证后,Microsoft 身份验证将使用授权码将用户重定向到 /authorized 路由。
  3. 获取令牌和用户详细信息: /authorized 路由使用授权码来获取访问令牌。然后,该令牌用于向 Microsoft Graph API 发出请求,以获取用户的详细信息。
  4. 注销: /logout 路由会清除用户会话并将其重定向到 Microsoft 身份验证以清除其单点登录状态。

在本地运行应用程序时进行身份验证:

  1. 需要将本地运行的应用程序的重定向 URI 添加到 Azure 应用注册中的重定向 URI 列表中。
  2. 使用 python app.py 启动的应用程序。
  3. 在 Web 浏览器中访问的应用程序。应该会被重定向到 Microsoft 身份验证以登录。

这个更新后的代码示例使用授权码流来获取用户详细信息,并提供登录和注销功能。它还包括使用 acquire_token_silent 方法从缓存中获取令牌以进行后续 API 调用的机制,从而提供更流畅的用户体验。

标签:python,azure,plotly-dash,azure-appservice,azure-authentication
From: 78832865

相关文章

  • 使用 Python 打印此图案
    1010101010101010使用python打印此我已经尝试过defprint_pattern(rows):foriinrange(rows):start_char='1'ifi%2==0else'0'pattern=''.join(start_charifj%2==0else('0'ifs......
  • python discord bot nextcord 斜线命令 更改语言
    我想根据用户的不和谐语言更改斜杠命令的名称。如果语言是韩语/서버如果语言是英语/服务器像这样。我可以使用ctx.locale更改里面的内容,但我也想更改名称和描述。我应该怎么办?当我问ChatGPT时,他们说的很奇怪,谷歌上也没有任何信息。但是有一个机器人可以根据语言......
  • 学习Python的书籍推荐--《Python编程从入门到实践》
    版权信息:书名:Python编程:从入门到实践(第3版)作者:[美]埃里克·马瑟斯(EricMatthes)译者:袁国忠评价:1.北京邮电大学副教授陈光老师是这样评价的:    编程教学之道,一是重在实践,二是循序渐进一一通过巧妙的实战项目,激发和保持学习的热情,让学习渐入佳境。在这两方......
  • 我可以将 Python 与 javascript 结合起来用于网站或应用程序吗
    我不知道如果j添加Python和javascript可以吗我尝试过。但决定在继续之前询问一下是否可以继续但是如果我只使用javascript还是只使用python会更好吗?我只需要建议或答案将Python与Javascript结合用于网站或应用程序不仅完全可行,而且也是一种非常常见的做法!二者......
  • Python 网络抓取与请求和美丽的汤被需要 javascript 阻止
    我正在尝试从网站上抓取文本。我使用简单的代码:requests.get(url_here)。我的代码直到最近才有效。现在,当我使用请求时,我收到一条消息,而不是获取网站的文本:“该网站需要启用JavaScript!您使用的浏览器不支持JavaScript,或者已关闭JavaScript。“我已验证我的浏览器确实......
  • python实现局域网及广域网私人聊天(Socket库局域网应用)
    引言在当今这个数字化时代,即时通讯已成为我们日常生活的一部分。无论是通过手机还是电脑,人们都在寻找更高效、更私密的沟通方式。想象一下,在你自己的局域网内,与朋友或同事建立一个专属的聊天室,无需担心数据泄露或者被第三方监听。本文将引导你从零开始,利用Python和Socket库......
  • 使用 python 抓取网页
    我有以下网页</div><ahref="https://www.emag.ro/laptop-lenovo-thinkbook-15-iil-cu-procesor-intel-core-i7-1065g7-pana-la-3-90-ghz-15-6-full-hd-16gb-512gb-ssd-intel-iris-plus-graphics-free-dos-mineral-grey-20sm003jrm/pd/DKBK1TMBM/#reviews-section&......
  • Python:需要有关类方法的帮助
    我有一个类“Duck”和“Dog”,如下所示:classDuck:defquack(self):print("quack")classDog:defbark(self):print("Ijustbark")以两种方式定义了另一个类并启动:case:1classItQuacks:def__init__(self,animal):......
  • 查找分层股东关系:在 python 中重构嵌套 if
    我想找到公司之间的股东关系。在下面的示例中,“人员1”直接拥有“公司1”50%的股份,那么需要检查“公司1”是否也拥有其他公司的股份。“公司1”拥有“公司2”50%的股份,“公司3”拥有20%的股份。这意味着“人员1”间接拥有“公司2”和“公司3”的部分股份。此......
  • 解决Python的pip问题:WARNING: Retrying (Retry(total=1, connect=None, read=None, re
    相关:pip安装第三方库报错Retrying(Retry(total=1,connect=None,read=None,redirect=None,status=None))国内镜像源下载常用国内源:清华:https://pypi.tuna.tsinghua.edu.cn/simple/阿里云:http://mirrors.aliyun.com/pypi/simple/中国科技大学https://pypi.mirrors.u......