Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Un agente usa OAuth per accedere agli utenti e ottenere token per le risorse a valle (come Microsoft Graph) senza gestire le credenziali. Il servizio Azure Bot gestisce lo scambio dei token e l'agente recupera il token dell'utente risultante durante un turno.
Panoramica
L'uso di OAuth in un agente comporta tre attività:
- Configura OAuth su Azure Bot e registrazione app: crea una o più connessioni OAuth sulla tua risorsa Azure Bot, ciascuna supportata da una registrazione dell'app Microsoft Entra ID. Aggiungi l'autorizzazione utente usando la credenziale di identità federata copre l'approccio più comune. Sono supportati anche altri tipi di credenziali, come i segreti client o i certificati. Per l'insieme completo di opzioni, vedi Basi dell'autenticazione del servizio Bot.
- Configura le impostazioni corrispondenti nell'agente: ogni connessione OAuth in Azure Bot si mappa a un gestore OAuth nella configurazione dell'agente. Vedi Impostazioni. Per la configurazione generale degli agenti, consulta Cos'è SDK per agenti Microsoft 365.
- Usa i token in codice: durante un turno, recupera il token utente, o effettua uno scambio On-Behalf-Of (OBO), tramite l'API di autorizzazione utente dell'agente. Vedi Usa il token in codice (non-OBO) e Usa il token in codice (OBO).
Tieni a mente i seguenti concetti mentre leggi il resto di questo articolo:
- Un Azure Bot può contenere più connessioni OAuth. Ad esempio, una connessione per Microsoft Graph e un'altra per GitHub. Ogni connessione è configurata indipendentemente in Azure Bot.
- C'è una relazione 1:1 tra una connessione OAuth in Azure Bot e un gestore OAuth nell'agente. L'impostazione
AzureBotOAuthConnectionNamedi un gestore dà il nome alla connessione Azure Bot che utilizza. Per usare due connessioni, definiamo due gestori. - L'API di autorizzazione utente dell'agente è la superficie che chiami nel codice. In .NET questo è
AgentApplication.UserAuthorization, ad esempioGetTurnTokenAsyncper leggere un token edExchangeTurnTokenAsyncper eseguire uno scambio OBO. Le superfici equivalenti sonoauthorizationin JavaScript eauthin Python.
Per esempi funzionanti, consulta l'accesso automatico e gli esempi OBO per:
Supporto della lingua per OAuth
L'SDK per agenti supporta OAuth per .NET, JavaScript e Python. I concetti fondamentali sono gli stessi in ogni linguaggio: gestori OAuth, collegamento di gestore alle route e scambio OBO. Solo il formato di configurazione e i nomi delle API dei gestori differiscono:
| Lingua | Dove si effettua la configurazione | Superficie API |
|---|---|---|
| .NET |
appsettings.json (o codice in Program.cs) |
AgentApplication.UserAuthorization |
| JavaScript | Variabili di ambiente .env |
AgentApplication.authorization |
| Python | Variabili di ambiente .env |
AgentApplication.auth |
Per JavaScript e Python, le chiavi .env usano gli stessi nomi gerarchici della struttura .NET appsettings.json , con ogni livello separato da un doppio carattere di sottolineatura (__). Le chiavi JavaScript mantengono i nomi delle foglie in notazione camel mostrati nelle tabelle (ad esempio, azureBotOAuthConnectionName). Le chiavi Python sono maiuscole (ad esempio, AZUREBOTOAUTHCONNECTIONNAME).
Importante
L'accesso automatico globale (AutoSignIn) e DefaultHandlerName sono supportati solo in .NET. In JavaScript e Python, si collegano gestori OAuth a route specifiche, come mostrato nella configurazione per route.
Impostazioni
Un oggetto autorizzazione utente all'interno di AgentApplication controlla come l'agente acquisisce i token utente. Ogni gestore dà almeno un nome alla connessione Azure Bot OAuth che utilizza. I seguenti esempi mostrano la struttura minima in ogni linguaggio. Le tabelle che seguono descrivono il resto delle proprietà disponibili, e le sezioni OBO coprono le impostazioni OBOConnectionName e OBOScopes.
In .NET, configura l'autorizzazione utente sotto AgentApplication in appsettings.json:
"AgentApplication": {
"UserAuthorization": {
"DefaultHandlerName": "{{handler-name}}",
"AutoSignIn": true | false,
"Handlers": {
"{{handler-name}}": {
"Settings": {
"AzureBotOAuthConnectionName": "{{azure-bot-connection-name}}"
}
}
}
}
}
In JavaScript, configura l'autorizzazione utente con variabili di ambiente nel file .env:
# Connection used to authenticate the agent itself
connections__serviceConnection__settings__clientId=
connections__serviceConnection__settings__clientSecret=
connections__serviceConnection__settings__tenantId=
connectionsMap__0__connection=serviceConnection
connectionsMap__0__serviceUrl=*
# OAuth handler named "{{handler-name}}"
AgentApplication__UserAuthorization__Handlers__{{handler-name}}__Settings__azureBotOAuthConnectionName={{azure-bot-connection-name}}
In Python, configura l'autorizzazione utente con variabili di ambiente nel file .env:
# Connection used to authenticate the agent itself
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTID=
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTSECRET=
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__TENANTID=
# OAuth handler named "{{handler-name}}"
AGENTAPPLICATION__USERAUTHORIZATION__HANDLERS__{{handler-name}}__SETTINGS__AZUREBOTOAUTHCONNECTIONNAME={{azure-bot-connection-name}}
Proprietà UserAuthorization
La tabella seguente elenca le proprietà di primo livello di UserAuthorization che determinano come vengono selezionati i gestori e come i token vengono acquisiti per ogni attività in ingresso.
| Proprietà | Richiesto | Type | Descrizione |
|---|---|---|---|
DefaultHandlerName |
No (non consigliato) | string | Solo .NET. Nome del gestore assegnato quando AutoSignIn restituisce true e non viene specificato alcun override per percorso. |
AutoSignIn |
No | bool o delegato | Solo .NET. Quando il valore è true (predefinito), l'agente tenta di acquisire un token per ogni attività in arrivo. Sovrascrivi in fase di esecuzione con Options.AutoSignIn per filtrare i tipi di attività. |
Handlers |
Sì (almeno uno) | oggetto (dizionario) | Mapping dei nomi dei gestori alle relative configurazioni. Ogni chiave deve essere univoca. |
In .NET, per limitare a quali attività si applica l'accesso automatico, imposta un predicato simile a: Options.AutoSignIn = (context, ct) => Task.FromResult(context.Activity.IsType(ActivityTypes.Message));. JavaScript e Python non supportano l'accesso automatico globale. Invece, esegui l'accesso per ambito collegando i nomi specifici dei gestori a singole route, come mostrato negli esempi per percorso.
Proprietà impostazioni
La tabella seguente descrive l'oggetto Settings annidato applicato a un singolo gestore OAuth, che controlla la presentazione della scheda di accesso, il comportamento dei tentativi di ripetizione, i timeout e la configurazione opzionale dello scambio OBO.
| Proprietà | Richiesto | Type | Descrizione |
|---|---|---|---|
AzureBotOAuthConnectionName |
Sì | string | Nome della connessione OAuth definito sulla risorsa bot di Azure. |
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, puoi chiamare ExchangeTurnTokenAsync manualmente. |
Title |
No | string | Titolo della scheda di accesso personalizzata Si imposta su 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 inserisce un codice non valido. Il valore predefinito è 2. |
InvalidSignInRetryMessage |
No | string | Messaggio mostrato dopo un inserimento di codice non valido. Il messaggio predefinito è Codice di accesso non valido. Inserire il codice a 6 cifre. |
Timeout |
No | int (ms) | Numero di millisecondi prima che un tentativo di accesso in corso scada. Il valore predefinito è 900.000 (15 minuti). |
Nota
AzureBotOAuthConnectionName, OBOConnectionName, OBOScopes, Title, e Text si applicano a tutti e tre i linguaggi (usando le lettere maiuscole e minuscole della chiave per linguaggio come descritto in Supporto linguistico per OAuth).
InvalidSignInRetryMax, InvalidSignInRetryMessage, e Timeout sono le impostazioni .NET.
Quale tipo si deve usare?
Consulta la seguente tabella per decidere quale approccio si adatta al tuo scenario.
| Scelta | Utilizzare se |
|---|---|
| Accesso automatico (solo .NET) | Vuoi che ogni attività in arrivo acquisisca automaticamente un token oppure vuoi che solo un sottoinsieme filtrato (ad esempio, solo i messaggi o tutto tranne gli eventi) lo faccia, fornendo un predicato a UserAuthorizationOptions.AutoSignIn. Supportato solo in .NET. |
| Per-route | Solo alcuni gestori di route necessitano di token oppure percorsi diversi devono utilizzare connessioni OAuth diverse (e quindi token diversi). Questa opzione è l'unica in JavaScript e Python. In .NET, si tratta di un componente aggiuntivo con l'accesso automatico globale. Se entrambi sono abilitati in .NET, il turno ha accesso ai token da entrambi. |
Usare il token nel codice (non OBO)
Questa sezione mostra come recuperare e utilizzare il token utente restituito direttamente dalla tua connessione OAuth del bot di Azure senza effettuare uno scambio On‑Behalf‑Of. In .NET, puoi usare l'accesso automatico globale o gestori per route. JavaScript e Python usano solo gestori per route. All'interno del tuo gestore di attività, recupera il token (GetTurnTokenAsync in .NET, authorization.getToken in JavaScript, auth.get_token in Python) il più tardi possibile così che l'SDK possa aggiornare il token se è vicino alla scadenza. I seguenti esempi illustrano entrambi i modelli.
Accesso automatico (solo .NET)
Nota
L'accesso automatico globale e DefaultHandlerName sono disponibili solo in .NET. Per JavaScript e Python, usa la configurazione per route.
Utilizza questa configurazione quando l'accesso automatico globale deve ottenere un token per ogni attività in ingresso senza la necessità di specificare gestori per route.
"AgentApplication": {
"UserAuthorization": {
"DefaultHandlerName": "auto",
"Handlers": {
"auto": {
"Settings": {
"AzureBotOAuthConnectionName": "teams_sso",
}
}
}
}
},
Il codice dell'agente sarà simile a:
public class MyAgent : AgentApplication
{
[MessageRoute]
public async Task OnMessageAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken cancellationToken)
{
var token = await UserAuthorization.GetTurnTokenAsync(turnContext);
// use the token
}
}
Configurazione per route
Utilizza una configurazione per route quando desideri un controllo granulare: solo le route che contrassegni esplicitamente acquisiscono token. La configurazione per route presenta i seguenti vantaggi:
- Riduce il recupero inutile dei token.
- Permette a route diverse di puntare a connessioni OAuth distinte (e quindi risorse o ambiti differenti).
- Ti permette di mescolare route autenticate e non autenticate all'interno dello stesso agente.
Nell'esempio seguente un singolo gestore graph è collegato solo alla route dei messaggi.
In .NET, l'accesso automatico globale è disabilitato e il gestore graph viene collegato alla route usando autoSignInHandlers.
"AgentApplication": {
"UserAuthorization": {
"AutoSignIn": false,
"Handlers": {
"graph": {
"Settings": {
"AzureBotOAuthConnectionName": "teams_sso",
}
}
}
}
},
Il codice dell'agente sarà simile a:
public class MyAgent : AgentApplication
{
[MessageRoute(autoSignInHandlers: "graph")]
public async Task OnMessageAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken cancellationToken)
{
var token = await UserAuthorization.GetTurnTokenAsync(turnContext, "graph");
// use the token
}
}
In JavaScript, passa un array di nomi di gestori come ultimo argomento alla registrazione della route. Solo questa route attiva l'accesso per il gestore graph.
AgentApplication__UserAuthorization__Handlers__graph__Settings__azureBotOAuthConnectionName=teams_sso
AgentApplication__UserAuthorization__Handlers__graph__Settings__title=Graph Sign In
AgentApplication__UserAuthorization__Handlers__graph__Settings__text=Sign in with Microsoft Graph
Il codice dell'agente sarà simile a:
class MyAgent extends AgentApplication {
constructor () {
super({ storage: new MemoryStorage() })
// the `graph` handler runs only for this route
this.onMessage('-me', this._profileRequest, ['graph'])
}
private _profileRequest = async (context, state) => {
const tokenResponse = await this.authorization.getToken(context, 'graph')
// use tokenResponse.token
}
}
In Python, passa auth_handlers al decoratore della route. Solo questa route attiva l'accesso per il gestore GRAPH.
AGENTAPPLICATION__USERAUTHORIZATION__HANDLERS__GRAPH__SETTINGS__AZUREBOTOAUTHCONNECTIONNAME=teams_sso
Il codice dell'agente sarà simile a:
@AGENT_APP.message(re.compile(r"^/(me|profile)$", re.IGNORECASE), auth_handlers=["GRAPH"])
async def profile_request(context: TurnContext, state: TurnState) -> None:
token_response = await AGENT_APP.auth.get_token(context, "GRAPH")
# use token_response.token
Recuperare il token durante un turno
Recupera il token utente ogni volta che è necessario durante un turno. Puoi chiamarlo più volte. Chiamalo immediatamente prima dell'uso, così la logica di aggiornamento (se necessaria) viene gestita in modo trasparente.
| Lingua | Chiama |
|---|---|
| .NET |
GetTurnTokenAsync(turnContext, handlerName) |
| JavaScript | authorization.getToken(context, handlerName) |
| Python | auth.get_token(context, handler_name) |
Usare il token nel codice (OBO)
On-Behalf-Of (OBO) si basa sul fatto che l'accesso iniziale dell'utente restituisce un token scambiabile. Questo richiede che gli scope della connessione OAuth includano uno che corrisponda a un scope esposto dall'API a valle (ad esempio, se l'ambito esposto è defaultScopes, l'ambito configurato potrebbe essere api://botid-{{clientId}}/defaultScopes). L'SDK degli agenti esegue quindi uno scambio Libreria di autenticazione Microsoft (MSAL) utilizzando una connessione configurata identificata da OBOConnectionName e l'elenco di OBOScopes. Quando OBOConnectionName e OBOScopes sono presenti nella configurazione, lo scambio avviene automaticamente e si ottiene il token finale tramite la chiamata token standard (GetTurnTokenAsync / getToken / get_token). Se manca uno dei due, puoi eseguire lo scambio esplicitamente durante l'esecuzione (ExchangeTurnTokenAsync in .NET, authorization.exchangeToken in JavaScript, auth.exchange_token in Python), permettendoti di risolvere dinamicamente la connessione o la lista di ambiti.
OBO nella configurazione
Usa questo modello quando conosci le risorse a valle e gli ambiti di cui hai bisogno al momento della 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 quella del token standard restituiscono direttamente il token OBO senza bisogno di codice aggiuntivo a runtime.
"AgentApplication": {
"UserAuthorization": {
"AutoSignIn": false,
"Handlers": {
"graph": {
"Settings": {
"AzureBotOAuthConnectionName": "teams_sso",
"OBOConnectionName": "ServiceConnection",
"OBOScopes": [
"https://graph.microsoft.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
{
[MessageRoute(autoSignInHandlers: "graph")]
public async Task OnMessageAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken cancellationToken)
{
// returns the OBO token because OBOConnectionName and OBOScopes are configured
var token = await UserAuthorization.GetTurnTokenAsync(turnContext, "graph");
// use the token
}
}
In JavaScript, definisci una connessione OBO nel mapping delle connessioni e ne fai riferimento nel gestore con oboConnectionName e oboScopes.
# Agent's own connection
connections__serviceConnection__settings__clientId=
connections__serviceConnection__settings__clientSecret=
connections__serviceConnection__settings__tenantId=
# OBO connection
connections__oboConnection__settings__clientId=
connections__oboConnection__settings__clientSecret=
connections__oboConnection__settings__tenantId=
connectionsMap__0__connection=serviceConnection
connectionsMap__0__serviceUrl=*
connectionsMap__1__connection=oboConnection
connectionsMap__1__serviceUrl=obo
AgentApplication__UserAuthorization__Handlers__graph__Settings__azureBotOAuthConnectionName=teams_sso
AgentApplication__UserAuthorization__Handlers__graph__Settings__oboConnectionName=oboConnection
AgentApplication__UserAuthorization__Handlers__graph__Settings__oboScopes=https://graph.microsoft.com/.default
Il codice dell'agente sarà simile a:
class MyAgent extends AgentApplication {
constructor () {
super({ storage: new MemoryStorage() })
this.onActivity('message', this._onMessage, ['graph'])
}
private _onMessage = async (context, state) => {
// returns the OBO token because oboConnectionName and oboScopes are configured
const tokenResponse = await this.authorization.getToken(context, 'graph')
// use tokenResponse.token
}
}
In Python, definisci una connessione OBO sotto CONNECTIONS e nel fai riferimento nel gestore con OBOCONNECTIONNAME e OBOSCOPES.
# Agent's own connection
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTID=
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTSECRET=
CONNECTIONS__SERVICE_CONNECTION__SETTINGS__TENANTID=
# OBO connection
CONNECTIONS__OBO__SETTINGS__CLIENTID=
CONNECTIONS__OBO__SETTINGS__CLIENTSECRET=
CONNECTIONS__OBO__SETTINGS__TENANTID=
AGENTAPPLICATION__USERAUTHORIZATION__HANDLERS__GRAPH__SETTINGS__AZUREBOTOAUTHCONNECTIONNAME=teams_sso
AGENTAPPLICATION__USERAUTHORIZATION__HANDLERS__GRAPH__SETTINGS__OBOCONNECTIONNAME=OBO
AGENTAPPLICATION__USERAUTHORIZATION__HANDLERS__GRAPH__SETTINGS__OBOSCOPES=https://graph.microsoft.com/.default
Il codice dell'agente sarà simile a:
@AGENT_APP.message(re.compile(r".*"), auth_handlers=["GRAPH"])
async def on_message(context: TurnContext, state: TurnState) -> None:
# returns the OBO token because OBOCONNECTIONNAME and OBOSCOPES are configured
token_response = await AGENT_APP.auth.get_token(context, "GRAPH")
# use token_response.token
OBO Exchange in fase di esecuzione
Usa uno scambio di runtime quando non riesci a sistemare la risorsa a valle, gli ambiti o la connessione nella configurazione. Questa situazione si verifica, ad esempio, quando gli ambiti dipendono dal tenant (tenant), dal ruolo utente o da un flag di funzionalità. In questo modello, opzionalmente configuri la connessione OBO, poi chiami il metodo di scambio con gli ambiti che decidi al momento del turno. Ricevi un token scambiato che puoi applicare immediatamente.
Chiama ExchangeTurnTokenAsync con gli ambiti che decidi al turno.
"AgentApplication": {
"UserAuthorization": {
"AutoSignIn": false,
"Handlers": {
"graph": {
"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
{
[MessageRoute(autoSignInHandlers: "graph")]
public async Task OnMessageAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken cancellationToken)
{
var scopes = GetScopes();
var exchangedToken = await UserAuthorization.ExchangeTurnTokenAsync(turnContext, "graph", exchangeScopes: scopes);
// use the token
}
}
Chiama authorization.exchangeToken con il nome del gestore e gli ambiti che decidi al turno.
connections__oboConnection__settings__clientId=
connections__oboConnection__settings__clientSecret=
connections__oboConnection__settings__tenantId=
connectionsMap__1__connection=oboConnection
connectionsMap__1__serviceUrl=obo
AgentApplication__UserAuthorization__Handlers__graph__Settings__azureBotOAuthConnectionName=teams_sso
AgentApplication__UserAuthorization__Handlers__graph__Settings__oboConnectionName=oboConnection
Il codice dell'agente sarà simile a:
class MyAgent extends AgentApplication {
constructor () {
super({ storage: new MemoryStorage() })
this.onActivity('message', this._onMessage, ['graph'])
}
private _onMessage = async (context, state) => {
const scopes = getScopes()
const exchangedToken = await this.authorization.exchangeToken(context, 'graph', { scopes })
// use exchangedToken.token
}
}
Chiama auth.exchange_token con gli ambiti che decidi al turno e il nome del gestore.
CONNECTIONS__MCS__SETTINGS__CLIENTID=
CONNECTIONS__MCS__SETTINGS__CLIENTSECRET=
CONNECTIONS__MCS__SETTINGS__TENANTID=
AGENTAPPLICATION__USERAUTHORIZATION__HANDLERS__MCS__SETTINGS__AZUREBOTOAUTHCONNECTIONNAME=teams_sso
AGENTAPPLICATION__USERAUTHORIZATION__HANDLERS__MCS__SETTINGS__OBOCONNECTIONNAME=MCS
Il codice dell'agente sarà simile a:
@AGENT_APP.message(re.compile(r".*"), auth_handlers=["MCS"])
async def on_message(context: TurnContext, state: TurnState) -> None:
scopes = get_scopes()
token_response = await AGENT_APP.auth.exchange_token(context, scopes, "MCS")
# use token_response.token
Impostazioni regionali OAuth
Per le regioni non statunitensi, aggiorna l'endpoint del servizio token che il tuo agente utilizza.
L'esempio seguente mostra una configurazione .NET. Aggiungila a appsettings.json:
"RestChannelServiceClientFactory": {
"TokenServiceEndpoint": "{{service-endpoint-uri}}"
}
Per service-endpoint-url, usa il valore appropriato dalla seguente tabella per i bot del cloud pubblico con residenza 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 |