Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Un agente utiliza OAuth para iniciar sesión con los usuarios y obtener tokens para recursos posteriores (como Microsoft Graph) sin gestionar las credenciales él mismo. Azure Bot Service administra el intercambio de tokens, y el agente recupera el token de usuario resultante durante un turno.
Información general
Usar OAuth en un agente implica tres actividades:
- Configurar OAuth en el Azure Bot y el registro de aplicaciones: cree una o más conexiones OAuth en su recurso de Azure Bot, cada una de ellas respaldada por un registro de la aplicación Microsoft Entra ID. Agregar autorización de usuario usando credencial de identidad federada abarca el enfoque más común. También se admiten otros tipos de credenciales, como secretos de cliente o certificados. Para ver el conjunto completo de opciones, consulte Conceptos básicos de autenticación de Bot Service.
- Configurar la configuración correspondiente en el agente: cada conexión OAuth en Azure Bot se asigna a un controlador OAuth en la configuración del agente. Consulte Configuración. Para la configuración general de agentes, consulte Qué es el SDK de Agentes de Microsoft 365
- Utilizar los tokens en código: durante un turno, recupere el token de usuario —o realice un intercambio On-Behalf-Of (OBO)— a través de la API de autorización de usuario del agente. Consulta Usar el token en código (no OBO) y Usar el token en código (OBO).
Tenga en cuenta los siguientes conceptos mientras lees el resto de este artículo:
- Un Azure Bot puede contener varias conexiones OAuth. Por ejemplo, una conexión para Microsoft Graph y otra para GitHub. Cada conexión se configura de manea independiente en el Azure Bot.
- Hay una relación 1:1 entre una conexión OAuth en Azure Bot y un gestor OAuth en el agente. La configuración
AzureBotOAuthConnectionNamede un controlador nombra la conexión de Azure Bot que utiliza. Para usar dos conexiones, definamos dos controladores. - La API de autorización de usuario del agente es la superficie que llama en el código. En .NET esto es
AgentApplication.UserAuthorization—por ejemplo,GetTurnTokenAsyncpara leer un token yExchangeTurnTokenAsyncpara realizar un intercambio OBO. Las superficies equivalentes sonauthorizationen JavaScript yauthen Python.
Para muestras que funcionan, consulte el inicio de sesión automático y las muestras OBO para:
Compatibilidad con OAuth
El SDK de Agentes es compatible con OAuth para .NET, JavaScript y Python. Los conceptos básicos son los mismos en todos los lenguajes: controladores OAuth, vinculación de controladores a rutas e intercambio OBO. Solo difieren el formato de configuración y los nombres de las API de los controladores:
| Language | Dónde configura | Superficie de la API |
|---|---|---|
| .NET |
appsettings.json (o código en Program.cs) |
AgentApplication.UserAuthorization |
| Javascript | Variables de entorno de .env |
AgentApplication.authorization |
| Python | Variables de entorno de .env |
AgentApplication.auth |
Para JavaScript y Python, las claves .env usan los mismos nombres jerárquicos que la estructura appsettings.json de .NET, con cada nivel separado por un doble guion bajo (__). Las claves de JavaScript mantienen los nombres de hojas camelCase que se muestran en las tablas (por ejemplo, azureBotOAuthConnectionName). Las claves de Python están en mayúsculas (por ejemplo, AZUREBOTOAUTHCONNECTIONNAME).
Importante
Inicio de sesión automático global (AutoSignIn) y DefaultHandlerName solo se admiten en .NET. En JavaScript y Python, se asocian controladores OAuth a rutas específicas, como se muestra en Configuración por ruta.
Configuración
Un objeto de autorización de usuario dentro de AgentApplication controla cómo adquiere el agente los tokens de usuario. Como mínimo, cada controlador nombra la conexión OAuth de Azure Bot que utiliza. Los siguientes ejemplos muestran la estructura mínima en cada lenguaje. Las tablas que siguen describen el resto de las propiedades disponibles, y las secciones de OBO abarcan la configuración de OBOConnectionName y OBOScopes.
En .NET, configurar la autorización de usuario bajo AgentApplication en appsettings.json:
"AgentApplication": {
"UserAuthorization": {
"DefaultHandlerName": "{{handler-name}}",
"AutoSignIn": true | false,
"Handlers": {
"{{handler-name}}": {
"Settings": {
"AzureBotOAuthConnectionName": "{{azure-bot-connection-name}}"
}
}
}
}
}
En JavaScript, configure la autorización de usuario con variables de entorno en el archivo .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}}
En Python, configure la autorización de usuario con variables de entorno en el archivo .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}}
Propiedades de UserAuthorization
La siguiente tabla enumera las propiedades de nivel superior UserAuthorization que determinan cómo se seleccionan los manejadores y cómo se adquieren los tokens para cada actividad entrante.
| Propiedad | Obligatorio | Tipo | Description |
|---|---|---|---|
DefaultHandlerName |
No (recomendado) | cadena | Solo .NET. Nombre del controlador usado cuando AutoSignIn es evaluado como verdadero y no se especifica ninguna anulación por ruta. |
AutoSignIn |
No | bool o delegado | Solo .NET. Cuando es verdadero (predeterminado), el agente intenta adquirir un token para cada actividad entrante. Sobrescribir en tiempo de ejecución con Options.AutoSignIn para filtrar tipos de actividad. |
Handlers |
Sí (al menos uno) | objeto (diccionario) | Asignación del nombre del controlador a su configuración. Cada clave debe ser única. |
En .NET; para restringir a qué actividades se aplica el inicio de sesión automático, establezca un predicado similar a: Options.AutoSignIn = (context, ct) => Task.FromResult(context.Activity.IsType(ActivityTypes.Message));. JavaScript y Python no admiten inicio de sesión automático global. En su lugar, escale el inicio de sesión adjuntando nombres específicos de controladores a rutas individuales, como se muestra en los ejemplos por ruta.
Propiedades de configuración
La siguiente tabla describe el objeto anidado Settings que se aplica a un controlador OAuth individual, el cual controla la presentación de la tarjeta de inicio de sesión, el comportamiento de reintentos, los tiempos de espera y la configuración opcional de intercambio OBO.
| Propiedad | Obligatorio | Tipo | Descripción |
|---|---|---|---|
AzureBotOAuthConnectionName |
Sí | cadena | Nombre de la conexión OAuth definida en el recurso de Azure Bot. |
OBOConnectionName |
No (solo OBO) | cadena | Nombre de una conexión de SDK de agentes que se utiliza para realizar un intercambio de token de representación. |
OBOScopes |
No (solo OBO) | string[] | Ámbitos solicitados durante el intercambio OBO. Si se omite con OBOConnectionName, puede llamar manualmente a ExchangeTurnTokenAsync. |
Title |
No | cadena | Título de la tarjeta de inicio de sesión personalizada. El valor predeterminado es Iniciar sesión". |
Text |
No | cadena | Texto del botón de la tarjeta de inicio de sesión. El valor predeterminado es Inicie sesión. |
InvalidSignInRetryMax |
No | entero | Número máximo de intentos permitidos cuando el usuario introduce un código no válido. El valor predeterminado es 2. |
InvalidSignInRetryMessage |
No | cadena | Mensaje mostrado tras una entrada de código no válida. El valor predeterminado es Código de inicio de sesión no válido. Introduzca el código de 6 dígitos. |
Timeout |
No | int (ms) | Número de milisegundos hasta que expire un intento de inicio de sesión en curso. El valor predeterminado es 900000 (15 minutos). |
Nota
AzureBotOAuthConnectionName, OBOConnectionName, OBOScopes, Title y Text se aplican a los tres lenguajes (usando las mayúsculas de clave por lenguaje descrita en Compatibilidad de lenguaje con OAuth).
InvalidSignInRetryMax, InvalidSignInRetryMessage y Timeout son la configuración de .NET.
¿Qué tipo debe usar?
Utilice la siguiente tabla para decidir qué enfoque se adapta a su escenario.
| Opción | Usar cuando |
|---|---|
| Inicio de sesión automático (solo .NET) | Se desea que cada actividad entrante adquiera automáticamente un token, o se desea un subconjunto filtrado (por ejemplo, solo mensajes o todo excepto eventos) al proporcionar un predicado a UserAuthorizationOptions.AutoSignIn. Solo admitido en .NET. |
| Por ruta | Solo los controladores de rutas específicos necesitan tokens o diferentes rutas deben usar diferentes conexiones OAuth (y por lo tanto diferentes tokens). Esta opción es la única en JavaScript y Python. En .NET, esto se suma con el inicio de sesión automático global. Si ambos están habilitados en .NET, el turno tiene acceso a los tokens de cada uno. |
Usar el token en el código (no OBO)
Esta sección muestra cómo recuperar y usar el token de usuario devuelto directamente por su conexión Azure Bot OAuth sin realizar un intercambio On-Behalf-Of. En .NET, puede usar controladores por ruta o de inicio de sesión automático global. JavaScript y Python usan solo controladores por ruta. Dentro de tu controlador de actividad, recupere el token (GetTurnTokenAsync en .NET, authorization.getToken en JavaScript, auth.get_token en Python) lo más tarde posible para que el SDK pueda actualizar el token si está cerca de caducar. Los siguientes ejemplos ilustran ambos patrones.
Inicio de sesión automático (solo .NET)
Nota
Inicio de sesión automático global y DefaultHandlerName solo se admiten en .NET. Para JavaScript y Python, use Configuración por ruta.
Utilice esta configuración cuando el inicio de sesión automático global deba adquirir un token para cada actividad entrante sin necesidad de especificar manejadores por ruta.
"AgentApplication": {
"UserAuthorization": {
"DefaultHandlerName": "auto",
"Handlers": {
"auto": {
"Settings": {
"AzureBotOAuthConnectionName": "teams_sso",
}
}
}
}
},
El código del agente tendría un aspecto similar al siguiente:
public class MyAgent : AgentApplication
{
[MessageRoute]
public async Task OnMessageAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken cancellationToken)
{
var token = await UserAuthorization.GetTurnTokenAsync(turnContext);
// use the token
}
}
Configuración por ruta
Use una configuración por ruta cuando quiera un control detallado: solo las rutas que indique explícitamente adquieren tokens. La configuración por ruta tiene las siguientes ventajas:
- Reduce la recuperación innecesaria de tokens.
- Permite que diferentes rutas apunten a conexiones OAuth distintas (y por tanto diferentes recursos o ámbitos).
- Le permite mezclar rutas autenticadas y no autenticadas dentro del mismo agente.
En el siguiente ejemplo, un solo controlador graph está asignado únicamente a la ruta del mensaje.
En .NET, el inicio de sesión automático global está deshabilitado y el controlador de graph se asocia a la ruta usando autoSignInHandlers.
"AgentApplication": {
"UserAuthorization": {
"AutoSignIn": false,
"Handlers": {
"graph": {
"Settings": {
"AzureBotOAuthConnectionName": "teams_sso",
}
}
}
}
},
El código del agente tendría un aspecto similar al siguiente:
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
}
}
En JavaScript, pasa una matriz de nombres de controladores como el último argumento al registro de la ruta. Solo esa ruta desencadena el inicio de sesión para el controlador 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
El código del agente tendría un aspecto similar al siguiente:
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
}
}
En Python, pasa auth_handlers al decorador de rutas. Solo esa ruta desencadena el inicio de sesión para el controlador GRAPH.
AGENTAPPLICATION__USERAUTHORIZATION__HANDLERS__GRAPH__SETTINGS__AZUREBOTOAUTHCONNECTIONNAME=teams_sso
El código del agente tendría un aspecto similar al siguiente:
@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
Recuperar el token durante un turno
Recupere el token de usuario siempre que lo necesite durante un turno. Puede llamarlo varias veces. Llámelo inmediatamente antes de usarlo para que la lógica de actualización (si es necesario) se gestione de forma transparente.
| Language | Llamar |
|---|---|
| .NET |
GetTurnTokenAsync(turnContext, handlerName) |
| Javascript | authorization.getToken(context, handlerName) |
| Python | auth.get_token(context, handler_name) |
Usar el token en el código (no OBO)
On-Behalf-Of (OBO) depende de que el inicio de sesión inicial del usuario devuelva un token intercambiable. Eso requiere que los ámbitos de la conexión OAuth incluyan uno que corresponda a un ámbito expuesto por la API de destino (por ejemplo, si el ámbito expuesto es defaultScopes, el ámbito configurado podría ser api://botid-{{clientId}}/defaultScopes). El SDK de Agentes realiza entonces un intercambio de la Biblioteca de autenticación de Microsoft (MSAL) usando una conexión configurada identificada por OBOConnectionName y la lista de OBOScopes. Cuando OBOConnectionName y OBOScopes están presentes en la configuración, el intercambio ocurre automáticamente y obtendrá el token final a través de la llamada de token estándar (GetTurnTokenAsync / getToken / get_token). Si falta alguno de los dos, puede realizar el intercambio explícitamente en runtime (ExchangeTurnTokenAsync en .NET, authorization.exchangeToken en JavaScript, auth.exchange_token en Python), lo que le permite resolver dinámicamente la lista de conexiones o ámbitos.
OBO en la configuración
Utilice este patrón cuando conozca el recurso y los ámbitos que necesita en el momento de la configuración. Cuando se proporcionan tanto OBOConnectionName como OBOScopes, el SDK realiza automáticamente el intercambio de representación durante el inicio de sesión. Esto significa que las llamadas posteriores al método estándar para obtener tokens devuelven directamente el token OBO sin necesidad de código adicional en tiempo de ejecución.
"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"
]
}
}
},
El código del agente tendría un aspecto similar al siguiente:
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
}
}
En JavaScript, defina una conexión OBO en el mapa de conexiones y las referencias desde el controlador con oboConnectionName y 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
El código del agente tendría un aspecto similar al siguiente:
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
}
}
En Python, defina una conexión OBO bajo CONNECTIONS y haga referencia a ella desde el controlador con OBOCONNECTIONNAME y 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
El código del agente tendría un aspecto similar al siguiente:
@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 en tiempo de ejecución
Use un intercambio de runtime cuando no pueda arreglar el recurso posterior, los ámbitos o la conexión en la configuración. Esta situación ocurre, por ejemplo, cuando los ámbitos dependen del inquilino, el rol del usuario o una marca de característica. En este modelo, opcionalmente configura la conexión OBO y luego llama al método de intercambio con los ámbitos que decida en el momento del turno. Recibe un token de intercambio que puede aplicar inmediatamente.
Llame a ExchangeTurnTokenAsync con los ámbitos que decida en el momento del 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"
]
}
}
},
El código del agente tendría un aspecto similar al siguiente:
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
}
}
Llame a authorization.exchangeToken con los ámbitos y el nombre del controlador que decida en el momento del 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
El código del agente tendría un aspecto similar al siguiente:
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
}
}
Llame a auth.exchange_token con los ámbitos que decida en el momento del turno y el nombre del controlador.
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
El código del agente tendría un aspecto similar al siguiente:
@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
Configuraciones regionales de OAuth
En el caso de las regiones fuera de EE. UU., actualice el punto de conexión del servicio de tokens que utiliza su agente.
En el ejemplo siguiente se muestra la configuración de .NET. Agregarlo a appsettings.json:
"RestChannelServiceClientFactory": {
"TokenServiceEndpoint": "{{service-endpoint-uri}}"
}
Para service-endpoint-url, utilice el valor correspondiente de la siguiente tabla para bots en la nube pública con residencia de datos en la región especificada.
| URI | Región |
|---|---|
https://europe.api.botframework.com |
Europa |
https://unitedstates.api.botframework.com |
Estados Unidos |
https://india.api.botframework.com |
India |