Azure Web App启用AAD(SERVICE PRINCIPAL)认证


Web Python Flask 代码:

app.py:

import identity
import identity.web
from flask import Flask, redirect, render_template, request, session, url_for,jsonify
from flask_session import Session

import app_config


app = Flask(__name__)
app.config.from_object(app_config)
Session(app)

from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)

auth = identity.web.Auth(
    session=session,
    authority=app.config.get("AUTHORITY"),
    client_id=app.config["CLIENT_ID"],
    client_credential=app.config["CLIENT_SECRET"],
)

@app.route("/login")
def login():
    return render_template("login.html", version=identity.__version__, **auth.log_in(
        scopes=app_config.SCOPE1, # Have user consent to scopes during log-in
        redirect_uri=url_for("auth_response", _external=True), 
        ))

@app.route(app_config.REDIRECT_PATH)
def auth_response():
    result = auth.complete_log_in(request.args)
    if "error" in result:
        return render_template("auth_error.html", result=result)
    return redirect(url_for("index"))


@app.route("/logout")
def logout():
    return redirect(auth.log_out(url_for("index", _external=True)))

@app.before_request
def before():
    url = request.path
    print(url)
    pass_list = ['/logout', '/getAToken','/login']
    suffix = url.endswith('.png') or url.endswith('.css') or url.endswith('.js')
    if url in pass_list or suffix:
        pass
    elif not auth.get_user():
        return redirect(url_for("login"))
    else:
        pass

@app.route("/")
def index():
    user = auth.get_user()
    return render_template('index.html', user=user, version=identity.__version__)


@app.route("/token")
def token():
    token = auth.get_token_for_user(app_config.SCOPE2)
    if "error" in token:
        return redirect(url_for("login"))
    return jsonify(token)

@app.route("/user")
def user():
    user = auth.get_user()
    return jsonify(user)

# API End
# Main
if __name__ == "__main__":
    app.run()


app_config.py:

import os

# Application (client) ID of app registration
CLIENT_ID = 'fe861e91-b217f-4585-8dfa-ddaa7849b0b4'
# Application's generated client secret: never check this into source control!
CLIENT_SECRET = 'FyF8Q~O7f2m56QpRqjg_1op12QwH0j6DbjqEq.cCu'

# AUTHORITY = "https://login.microsoftonline.com/common"  # For multi-tenant app
AUTHORITY = f"https://login.microsoftonline.com/878d19338-a5c4-4f48-bd1c-2dbf8a70f3c5"

REDIRECT_PATH = "/getAToken"  # Used for forming an absolute URL to your redirect URI.
# The absolute URL must match the redirect URI you set
# in the app's registration in the Azure portal.

# You can find more Microsoft Graph API endpoints from Graph Explorer
# https://developer.microsoft.com/en-us/graph/graph-explorer
ENDPOINT = 'https://graph.microsoft.com/v1.0/users'  # This resource requires no admin consent

# You can find the proper permission names from this document
# https://docs.microsoft.com/en-us/graph/permissions-reference
#SCOPE = ["openid profile"]
SCOPE1 = ["User.ReadBasic.All"]
SCOPE2 = ["User.ReadBasic.All openid profile email"]

# Tells the Flask-session extension to store sessions in the filesystem
SESSION_TYPE = "filesystem"
# Using the file system will not work in most production systems,
# it's better to use a database-backed session store instead.



validateIDToken.py

#pip install azure-ad-verify-token

from azure_ad_verify_token import verify_jwt

azure_ad_app_id = 'fe861ed91-b27f-4585-8dfa-ddaa7849b0b4'
azure_ad_issuer = 'https://login.microsoftonline.com/878d1938-a5c4-4f48-bdd1c-2dbf8a70f3c5/v2.0'
azure_ad_jwks_uri = 'https://login.microsoftonline.com/878d1938-a5dc4-4f48-bd1c-2dbf8a70f3c5/discovery/v2.0/keys'

payload = verify_jwt(
    token= 'xxx',
    valid_audiences=azure_ad_app_id,
    issuer=azure_ad_issuer,
    jwks_uri=azure_ad_jwks_uri,
    verify=True,
)

print(payload)

#Signature verification failed
#Invalid authorization token

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Microsoft Identity Python Web App</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">Powered by Identity Web {{ version }}</footer>
</body>
</html>

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Microsoft Identity Python Web App</title>
</head>
<body>
    <h1>Microsoft Identity Python Web App</h1>
    <h2>Welcome {{ user.get("email") }}</h2>
    <hr>
    <a href="/logout">Logout</a><br/>
    <footer style="text-align: left">Powered by Identity Web {{ version }}</footer>
</body>
</html>