Python 访问&;通过Web应用程序操纵Azure AD B2C用户

Python 访问&;通过Web应用程序操纵Azure AD B2C用户,python,flask,azure-active-directory,azure-ad-b2c,msal,Python,Flask,Azure Active Directory,Azure Ad B2c,Msal,在使用Azure的广告B2C框架时,我正在努力进行基本的用户管理 我已经成功地设置了Azure AD B2C资源,注册了面向消费者的web应用程序(创建了一个客户端密码,并向User.ReadWrite.All授予了委托权限和应用权限),创建了自定义属性,并添加了开箱即用的注册和登录用户流。此外,我已经成功地将用户注册并登录到我的web应用程序 为了达到这一点,我遵循了文档中提供的Python示例(ms identity Python webapp master): app.py @app.ro

在使用Azure的广告B2C框架时,我正在努力进行基本的用户管理

我已经成功地设置了Azure AD B2C资源,注册了面向消费者的web应用程序(创建了一个客户端密码,并向User.ReadWrite.All授予了委托权限和应用权限),创建了自定义属性,并添加了开箱即用的注册和登录用户流。此外,我已经成功地将用户注册并登录到我的web应用程序

为了达到这一点,我遵循了文档中提供的Python示例(ms identity Python webapp master):

app.py

@app.route("/login")
def login():
    session["state"] = str(uuid.uuid4())
    # Technically we could use empty list [] as scopes to do just sign in,
    # here we choose to also collect end user consent upfront
    auth_url = _build_auth_url(scopes=app_config_b2c.SCOPE, state=session["state"])
    return render_template("templates/login.html", auth_url=auth_url, version=msal.__version__)

@app.route(app_config_b2c.REDIRECT_PATH)  # Its absolute URL must match your app's redirect_uri set in AAD
def authorized():
    if request.args.get('state') != session.get("state"):
        return redirect(url_for("index"))  # No-OP. Goes back to Index page
    if "error" in request.args:  # Authentication/Authorization failure
        return render_template("auth_error.html", result=request.args)
    if request.args.get('code'):
        cache = _load_cache()
        result = _build_msal_app(cache=cache).acquire_token_by_authorization_code(
            request.args['code'],
            scopes=app_config_b2c.SCOPE,  # Misspelled scope would cause an HTTP 400 error here
            redirect_uri=url_for("authorized", _external=True))
        if "error" in result:
            return render_template("auth_error.html", result=result)
        session["user"] = result.get("id_token_claims")
        _save_cache(cache)
    return redirect(url_for("index"))

@app.route("/logout")
def logout():
    session.clear()  # Wipe out user and its token cache from session
    return redirect(  # Also logout from your tenant's web session
        app_config_b2c.AUTHORITY + "/oauth2/v2.0/logout" +
        "?post_logout_redirect_uri=" + url_for("index", _external=True))

@app.route("/graphcall")
def graphcall():
    token = _get_token_from_cache(app_config_b2c.SCOPE)
    if not token:
        return redirect(url_for("login"))
    graph_data = requests.get(  # Use token to call downstream service
        app_config_b2c.ENDPOINT,
        headers={'Authorization': 'Bearer ' + token['access_token']},
        ).json()
    return render_template('templates/display.html', result=graph_data)


def _load_cache():
    cache = msal.SerializableTokenCache()
    if session.get("token_cache"):
        cache.deserialize(session["token_cache"])
    return cache

def _save_cache(cache):
    if cache.has_state_changed:
        session["token_cache"] = cache.serialize()

def _build_msal_app(cache=None, authority=None):
    return msal.ConfidentialClientApplication(
        app_config_b2c.CLIENT_ID, authority=authority or app_config_b2c.AUTHORITY,
        client_credential=app_config_b2c.CLIENT_SECRET, token_cache=cache)

def _build_auth_url(authority=None, scopes=None, state=None):
    return _build_msal_app(authority=authority).get_authorization_request_url(
        scopes or [],
        state=state or str(uuid.uuid4()),
        redirect_uri=url_for("authorized", _external=True))

def _get_token_from_cache(scope=None):
    cache = _load_cache()  # This web app maintains one cache per session
    cca = _build_msal_app(cache=cache)
    accounts = cca.get_accounts()
    if accounts:  # So all account(s) belong to the current signed-in user
        result = cca.acquire_token_silent(scope, account=accounts[0])
        _save_cache(cache)
        return result
app\u config\u b2c.py

import os

b2c_tenant = "myapplication"
signupsignin_user_flow = "b2c_1_signupsignin1"
editprofile_user_flow = "b2c_1_profileediting1"
resetpassword_user_flow = "b2c_1_passwordreset1"
authority_template = "https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{user_flow}"

CLIENT_SECRET = "Enter_the_Client_Secret_Here" # Our Quickstart uses this placeholder
# In your production app, we recommend you to use other ways to store your secret,
# such as KeyVault, or environment variable as described in Flask's documentation here
# https://flask.palletsprojects.com/en/1.1.x/config/#configuring-from-environment-variables
# CLIENT_SECRET = os.getenv("CLIENT_SECRET")
# if not CLIENT_SECRET:
#     raise ValueError("Need to define CLIENT_SECRET environment variable")

AUTHORITY = authority_template.format(
    tenant=b2c_tenant, user_flow=signupsignin_user_flow)
B2C_PROFILE_AUTHORITY = authority_template.format(
    tenant=b2c_tenant, user_flow=editprofile_user_flow)
B2C_RESET_PASSWORD_AUTHORITY = authority_template.format(
    tenant=b2c_tenant, user_flow=resetpassword_user_flow)

CLIENT_ID = "xxx.xxxxxx"

REDIRECT_PATH = "/getAToken"  # It will be used to form an absolute URL
    # And that absolute URL must match your app's redirect_uri set in AAD

# This is the resource that you are going to access in your B2C tenant
ENDPOINT = 'https://graph.microsoft.com/v1.0/users'

# These are the scopes that you defined for the web API
SCOPE = ["User.ReadWrite.All"]

SESSION_TYPE = "filesystem"  # So token cache will be stored in server-side session
graphcall不能在这个框架内工作(可能是b2c问题),我确信这是问题的一部分,但最终我希望应用程序使用登录用户的广告属性(特别是我启用的自定义属性),并在必要时修改它们。例如,假设一个自定义属性是“付费订户”。当用户注册时,该属性为空。当用户购买内容时,我希望将属性的值设置为相关的值(如“true”)


这可能吗?我是否需要其他用户流?我在这里遗漏了什么(理论上和实践上)?

Microsoft Graph不支持Azure AD B2C发行的代币。 您需要有Azure AD生成的访问令牌

有一个使用Azure ad b2c自定义策略的过程,您可以在其中集成Microsoft Graph并向声明添加自定义属性

这有助于将Azure AD访问令牌获取到调用图,通过上述实现,phython代码中不会有太多更改


要添加自定义属性,请通过

Hi。Microsoft graph由Azure AD投影。因此,如果我们想调用Microsoft graph,我们需要执行Azure AD auth。有关详细信息,请参阅