Partie 4 : Exemple d’implémentation d’application principale

Partie précédente : Implémentation d’API tierce

L’application principale de ce scénario est une application Flask simple que vous déployez sur Azure App Service. L’application fournit un point de terminaison d’API public nommé /api/v1/getcode, qui génère un code à d’autres fins dans l’application (par exemple, avec l’authentification à deux facteurs pour les utilisateurs humains). L’application principale fournit également une page d’accueil simple qui affiche un lien vers le point de terminaison de l’API.

Le script d’approvisionnement de l’exemple effectue les étapes suivantes :

  1. Créez l’hôte App Service et déployez le code à l’aide de la commande Azure CLI. az webapp up

  2. Créez un compte de stockage Azure pour l’application principale à l’aide de az storage account create.

  3. Créez une file d’attente dans le compte de stockage appelé « code-requests » à l’aide de az storage queue create.

  4. Afin de vous assurer que l’application peut écrire dans la file d’attente, utilisez az role assignment create pour attribuer à l’application le rôle Contributeur aux données de file d’attente de stockage. Pour plus d’informations sur les rôles, consultez Comment attribuer des autorisations de rôle à l’aide d’Azure CLI.

Le code principal de l’application est le suivant. Les explications des détails importants sont fournies dans les prochaines parties de cette série.

from flask import Flask, request, jsonify
import requests, random, string, os
from datetime import datetime
from azure.keyvault.secrets import SecretClient
from azure.identity import DefaultAzureCredential
from azure.storage.queue import QueueClient

app = Flask(__name__)
app.config["DEBUG"] = True

number_url = os.environ["THIRD_PARTY_API_ENDPOINT"]

# Authenticate with Azure. First, obtain the DefaultAzureCredential
credential = DefaultAzureCredential()

# Next, get the client for the Key Vault. You must have first enabled managed identity
# on the App Service for the credential to authenticate with Key Vault.
key_vault_url = os.environ["KEY_VAULT_URL"]
keyvault_client = SecretClient(vault_url=key_vault_url, credential=credential)

# Obtain the secret: for this step to work you must add the app's service principal to
# the key vault's access policies for secret management.
api_secret_name = os.environ["THIRD_PARTY_API_SECRET_NAME"]
vault_secret = keyvault_client.get_secret(api_secret_name)

# The "secret" from Key Vault is an object with multiple properties. The key we
# want for the third-party API is in the value property. 
access_key = vault_secret.value

# Set up the Storage queue client to which we write messages
queue_url = os.environ["STORAGE_QUEUE_URL"]
queue_client = QueueClient.from_queue_url(queue_url=queue_url, credential=credential)


@app.route('/', methods=['GET'])
def home():
    return f'Home page of the main app. Make a request to <a href="./api/v1/getcode">/api/v1/getcode</a>.'


def random_char(num):
       return ''.join(random.choice(string.ascii_letters) for x in range(num))


@app.route('/api/v1/getcode', methods=['GET'])
def get_code():
    headers = {
        'Content-Type': 'application/json',
        'x-functions-key': access_key
        }

    r = requests.get(url = number_url, headers = headers)
    
    if (r.status_code != 200):       
        return "Could not get you a code.", r.status_code

    data = r.json()
    chars1 = random_char(3)
    chars2 = random_char(3)
    code_value = f"{chars1}-{data['value']}-{chars2}"
    code = { "code": code_value, "timestamp" : str(datetime.utcnow()) }

    # Log a queue message with the code for, say, a process that invalidates
    # the code after a certain period of time.
    queue_client.send_message(code)

    return jsonify(code)


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