Configurare l'agente per l'uso di OAuth

Innanzitutto, configura OAuth per un agente nella risorsa Azure Bot e nella registrazione dell'app corrispondente. Il runtime dell'agente acquisisce e aggiorna quindi i token utente tramite la AgentApplication funzionalità di accesso automatico. L'accesso automatico può essere eseguito a livello globale (tutti i tipi di attività) o in modo selettivo in modo che solo determinate route o tipi di attività richiedano un token.

È possibile registrare più gestori OAuth nella configurazione e assegnarli a route specifiche oppure dichiarare un singolo gestore predefinito usato ovunque. Ogni gestore può facoltativamente eseguire scambi per conto di (OBO) quando il lato Azure è configurato per supportarli. Per un avvio rapido, vedere l'esempio AutoSignIn o adattare la configurazione illustrata qui in un agente esistente.

Le sezioni seguenti descrivono come configurare UserAuthorization, decidere tra approcci globali e per route e recuperare i token (standard e OBO) durante un turno. Sono inoltre disponibili indicazioni regionali per le distribuzioni non statunitensi.

Supporto della lingua per OAuth

Agents SDK supporta OAuth per tutte le lingue. I dettagli sono simili tra lingue diverse. Gli esempi di codice in questo articolo sono specifici per .NET.

È possibile configurare un agente di .NET in appSettings.json o tramite codice in Program.cs. Questo articolo descrive come configurare usando appSettings.json.

Settings

Un UserAuthorization oggetto all'interno AgentApplication controlla il modo in cui l'agente acquisisce i token utente. Il codice JSON seguente e altri elementi simili nell'articolo illustrano la struttura gerarchica. Le tabelle che seguono descrivono ogni proprietà per UserAuthorization e per l'oggetto annidato Settings .

  "AgentApplication": {
    "UserAuthorization": {
      "DefaultHandlerName": "{{handler-name}}",
      "AutoSignIn": true | false,
      "Handlers": {
        "{{handler-name}}": {
          "Settings": {
            "AzureBotOAuthConnectionName": "{{azure-bot-connection-name}}",
            "OBOConnectionName": "{{connection-name}}",
            "OBOScopes": [
              "{{obo-scope}}"
            ],
            "Title": "{{signin-card-title}}",
            "Text": "{{signin-card-button-text}}",
            "InvalidSignInRetryMax": {{int}},
            "InvalidSignInRetryMessage": {{invalid-attempt-message}},
            "Timeout": {{timeout-ms}}
          }
        }
      }
    }
  }

Proprietà UserAuthorization

Nella tabella seguente sono elencate le proprietà di primo livello UserAuthorization che determinano la modalità di selezione dei gestori e la modalità di acquisizione dei token per ogni attività in ingresso.

Proprietà Obbligatorio Tipo Description
DefaultHandlerName No (scelta consigliata) string Nome del gestore assegnato quando AutoSignIn restituisce true e non viene specificato alcun override per percorso.
AutoSignIn No bool o delegato Se true (impostazione predefinita), l'agente tenta di acquisire un token per ogni attività in ingresso. Eseguire l'override in fase di esecuzione con Options.AutoSignIn per filtrare i tipi di attività.
Handlers Sì (almeno una) oggetto (dizionario) Mappatura del nome del gestore alla relativa configurazione. Ogni chiave deve essere univoca.

Per limitare le attività a cui si applica l'accesso automatico, impostare un predicato simile a: Options.AutoSignIn = (context, ct) => Task.FromResult(context.Activity.IsType(ActivityTypes.Message));.

Proprietà delle impostazioni

La tabella seguente descrive l'oggetto annidato Settings applicato a un singolo gestore OAuth, il controllo della presentazione della scheda di accesso, il comportamento di ripetizione dei tentativi, i timeout e la configurazione facoltativa dello scambio OBO.

Proprietà Obbligatorio Tipo Description
AzureBotOAuthConnectionName string Nome di connessione OAuth definito nella risorsa azure Bot.
OBOConnectionName No (solo OBO) string Nome di una connessione dell'agents SDK usata per eseguire uno scambio di token On-Behalf-Of.
OBOScopes No (solo OBO) string[] Ambiti richiesti durante lo scambio OBO. Se omesso con OBOConnectionName, è possibile chiamare ExchangeTurnTokenAsync manualmente.
Title No string Titolo della scheda di accesso personalizzata. L'impostazione predefinita è Accedi.
Text No string Testo del pulsante della scheda di accesso. L'impostazione predefinita è Accedi.
InvalidSignInRetryMax No int Numero massimo di tentativi consentiti quando l'utente immette un codice non valido. Il valore predefinito è 2.
InvalidSignInRetryMessage No string Messaggio visualizzato dopo l'inserimento di un codice non valido. L'impostazione predefinita è Codice di accesso non valido. Immettere il codice a 6 cifre.
Timeout No int (ms) Numero di millisecondi prima della scadenza di un tentativo di accesso in corso. Il valore predefinito è 900000 (15 minuti).

Quale tipo è necessario usare?

Usare la tabella seguente per decidere quale approccio si adatti allo scenario in uso.

Scelta Usa quando
Accesso automatico Si vuole che ogni attività in ingresso acquisisca automaticamente un token o si desideri un subset filtrato (ad esempio, solo i messaggi o tutti gli eventi tranne gli eventi) fornendo un predicato a UserAuthorizationOptions.AutoSignIn.
Per-route Solo i gestori di route specifici necessitano di token o route diverse devono usare connessioni OAuth diverse e pertanto token diversi. Questo approccio si aggiunge all'accesso automatico globale. Se entrambi sono abilitati, il turno ha accesso ai token da entrambi.

Usare il token nel codice (non OBO)

Questa sezione illustra come recuperare e usare il token utente restituito direttamente dalla connessione OAuth di Azure Bot senza eseguire uno scambio On-Behalf-Of. Decidere prima di tutto se si preferisce l'accesso automatico globale o i gestori per route. Quindi, all'interno del gestore attività, chiama GetTurnTokenAsync il più tardi possibile in modo che l'SDK possa aggiornare il token se è prossimo alla scadenza. Gli esempi seguenti illustrano entrambi i modelli.

Configurazione del solo accesso automatico

Utilizzare questa configurazione quando l'accesso automatico globale deve acquisire un token per ogni attività in ingresso senza dover specificare gestori per ogni percorso.

  "AgentApplication": {
    "UserAuthorization": {
      "DefaultHandlerName": "auto",
      "Handlers": {
        "auto": {
          "Settings": {
            "AzureBotOAuthConnectionName": "teams_sso",
          }
        }
      }
    }
  },

Il codice dell'agente sarà simile a:

public class MyAgent : AgentApplication
{
    public MyAgent(AgentApplicationOptions options) : base(options)
    {
        OnActivity(ActivityTypes.Message, OnMessageAsync, rank: RouteRank.Last);
    }

    public async Task OnMessageAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken cancellationToken)
    {
        var token = await UserAuthorization.GetTurnTokenAsync(turnContext);

        // use the token 
    }
}

Configurazione solo per itinerario

Usare una configurazione per route quando si vuole un controllo con granularità fine: solo le route contrassegnate in modo esplicito acquisiscono i token. La configurazione per route riduce il recupero di token non necessari, consente route diverse per le connessioni OAuth distinte (e quindi risorse o ambiti diversi) e consente di combinare route autenticate e non autenticate all'interno dello stesso agente. Nell'esempio seguente l'accesso automatico globale è disabilitato e un singolo messageOauth gestore è collegato solo alla route dei messaggi.

  "AgentApplication": {
    "UserAuthorization": {
      "AutoSignIn": false,
      "Handlers": {
        "messageOauth": {
          "Settings": {
            "AzureBotOAuthConnectionName": "teams_sso",
          }
        }
      }
    }
  },

Il codice dell'agente sarà simile a:

public class MyAgent : AgentApplication
{
    public MyAgent(AgentApplicationOptions options) : base(options)
    {
        OnActivity(ActivityTypes.Message, OnMessageAsync, rank: RouteRank.Last, autoSignInHandlers: ["messageOauth"]);
    }

    public async Task OnMessageAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken cancellationToken)
    {
        var token = await UserAuthorization.GetTurnTokenAsync(turnContext, "messageOauth");

        // use the token
    }
}

Usa GetTurnTokenAsync

Chiamare GetTurnTokenAsync ogni volta che è necessario il token utente durante un turno. È possibile richiamarlo più volte. Chiamarlo immediatamente prima dell'uso in modo che la logica di aggiornamento (se necessario) venga gestita in modo trasparente.

Usare il token nel codice (OBO)

On-Behalf-Of (OBO) si basa sull'accesso utente iniziale che restituisce un token scambiabile. Ciò richiede che gli ambiti della connessione OAuth includano uno che corrisponde a un ambito esposto dall'API downstream ( ad esempio se l'ambito esposto è defaultScopes, l'ambito configurato potrebbe essere api://botid-{{clientId}}/defaultScopes). Agents SDK esegue quindi uno scambio di Libreria di Autenticazione Microsoft (MSAL) usando una connessione configurata identificata da OBOConnectionName e l'elenco di OBOScopes. Quando nella configurazione sono presenti sia OBOConnectionName sia OBOScopes, lo scambio avviene automaticamente e si ottiene il token finale tramite GetTurnTokenAsync. Se non è presente, è possibile eseguire lo scambio in modo esplicito in fase di esecuzione con ExchangeTurnTokenAsync, consentendo di risolvere dinamicamente la connessione o l'elenco di ambiti.

OBO nella configurazione

Usare questo modello quando si conoscono le risorse downstream e gli ambiti necessari in fase di configurazione. Quando vengono specificati sia OBOConnectionName che OBOScopes, l'SDK esegue automaticamente lo scambio On‑Behalf‑Of durante l'accesso all'account. Ciò significa che le chiamate successive a GetTurnTokenAsync restituiscono il token OBO direttamente senza codice di runtime aggiuntivo necessario.

  "AgentApplication": {
    "UserAuthorization": {
      "DefaultHandlerName": "auto",
      "Handlers": {
        "auto": {
          "Settings": {
            "AzureBotOAuthConnectionName": "teams_sso",
            "OBOConnectionName": "ServiceConnection",
            "OBOScopes": [
              "https://myservicescope.com/.default"
            ]
          }
        }
      }
    }
  },
  "Connections": {
    "ServiceConnection": {
      "Settings": {
        "AuthType": "FederatedCredentials",
        "AuthorityEndpoint": "https://login.microsoftonline.com/{{TenantId}}",
        "ClientId": "{{ClientId}}",
        "FederatedClientId": "{{ManagedIdentityClientId}}",
        "Scopes": [
          "https://api.botframework.com/.default"
        ]
      }
    }
  },

Il codice dell'agente sarà simile a:

public class MyAgent : AgentApplication
{
    public MyAgent(AgentApplicationOptions options) : base(options)
    {
        OnActivity(ActivityTypes.Message, OnMessageAsync, rank: RouteRank.Last);
    }

    public async Task OnMessageAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken cancellationToken)
    {
        var token = await UserAuthorization.GetTurnTokenAsync(turnContext);

        // use the token
    }
}

OBO Exchange in fase di esecuzione

Usare uno scambio di dati a runtime quando la risorsa downstream, gli ambiti o anche la connessione da usare non può essere determinata in fase di configurazione, ad esempio quando gli ambiti dipendono da tenant, ruolo dell'utente o flag di funzionalità. In questo modello si configura (facoltativamente) OBOConnectionName, quindi si chiama ExchangeTurnTokenAsync con gli ambiti definiti al momento del turno, ricevendo un token ottenuto dallo scambio che è possibile usare immediatamente.

  "AgentApplication": {
    "UserAuthorization": {
      "DefaultHandlerName": "auto",
      "Handlers": {
        "auto": {
          "Settings": {
            "AzureBotOAuthConnectionName": "teams_sso",
            "OBOConnectionName": "ServiceConnection"
          }
        }
      }
    }
  },
  "Connections": {
    "ServiceConnection": {
      "Settings": {
        "AuthType": "FederatedCredentials",
        "AuthorityEndpoint": "https://login.microsoftonline.com/{{TenantId}}",
        "ClientId": "{{ClientId}}",
        "FederatedClientId": "{{ManagedIdentityClientId}}",
        "Scopes": [
          "https://api.botframework.com/.default"
        ]
      }
    }
  },

Il codice dell'agente sarà simile a:

public class MyAgent : AgentApplication
{
    public MyAgent(AgentApplicationOptions options) : base(options)
    {
        OnActivity(ActivityTypes.Message, OnMessageAsync, rank: RouteRank.Last);
    }

    public async Task OnMessageAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken cancellationToken)
    {
        var scopes = GetScopes();

        var exchangedToken = await UserAuthorization.ExchangeTurnTokenAsync(turnContext, exchangeScopes: scopes);

        // use the token
    }
}

Impostazioni OAuth internazionali

Per le aree non statunitensi, aggiornare l'endpoint del servizio token usato dall'agente.

Aggiungere il codice seguente a appsettings.json:

"RestChannelServiceClientFactory": {
   "TokenServiceEndpoint": "{{service-endpoint-uri}}"
}

Per service-endpoint-url, utilizzare il valore appropriato dalla tabella seguente per i bot cloud pubblici con localizzazione dei dati nella regione specificata.

URI Area geografica
https://europe.api.botframework.com Europa
https://unitedstates.api.botframework.com Stati Uniti
https://india.api.botframework.com India