Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Um agente usa OAuth para fazer login de usuários e obter tokens para recursos posteriores (como o Microsoft Graph) sem lidar com as próprias credenciais. O Serviço de Bot do Azure gerencia a troca do token, e o agente recupera o token de usuário resultante durante uma rodada.
Visão geral
O uso de OAuth em um agente envolve três atividades:
- Configurar OAuth no Azure Bot e no registro do aplicativo: crie uma ou mais conexões OAuth no recurso do Azure Bot, cada uma com o apoio de um registro de aplicativo do Microsoft Entra ID. Adicionar autorização do usuário usando credencial de identidade federada abrange a abordagem mais comum. Outros tipos de credencial, como segredos de cliente ou certificados, também são compatíveis. Para o conjunto de opções completo, consulte Noções básicas de autenticação do Serviço de Bot.
- Definir as configurações correspondentes no agente: cada conexão OAuth no Azure Bot é mapeada para um manipulador OAuth na configuração do agente. Consulte Configurações. Para configuração do agente geral, consulte O que é o SDK de Agentes do Microsoft 365.
- Usar os tokens em código: durante uma rodada, recupere o token de usuário, ou realize uma troca Em nome de (OBO), por meio da API de autorização do agente. Consulte Usar o token em código (não OBO) e Usar o token em código (OBO).
Tenha em mente os seguintes conceitos enquanto lê o restante deste artigo:
- Um bot do Azure pode conter várias conexões OAuth. Por exemplo, uma conexão para o Microsoft Graph e outra para o GitHub. Cada conexão é configurada independentemente no Bot do Azure.
- Existe uma relação 1:1 entre uma conexão OAuth no Bot do Azure e um manipulador OAuth no agente. A configuração
AzureBotOAuthConnectionNamedo manipulador nomeia a conexão do Bot do Azure usada por ela. Para usar duas conexões, defina dois manipuladores. - A API de autorização do usuário do agente é a superfície que você chama no código. No .NET, é
AgentApplication.UserAuthorization, por exemplo,GetTurnTokenAsyncpara ler um token eExchangeTurnTokenAsyncpara realizar uma troca OBO. As superfícies equivalentes sãoauthorizationem JavaScript eauthem Python.
Para amostras em funcionamento, consulte as credenciais automáticas e as amostras OBO para:
Suporte a linguagens para OAuth
O SDK de Agentes dá suporte a OAuth para .NET, JavaScript e Python. Os conceitos básicos são os mesmos em todas as linguagens: manipuladores OAuth, anexação de manipuladores a rotas e troca OBO. Somente o formato da configuração e os nomes de API do manipulador diferem:
| Linguagem | Onde você configura | Superfície da API |
|---|---|---|
| .NET |
appsettings.json (ou código em Program.cs) |
AgentApplication.UserAuthorization |
| JavaScript | Variáveis de ambiente .env |
AgentApplication.authorization |
| Python | Variáveis de ambiente .env |
AgentApplication.auth |
Para JavaScript e Python, as chaves .env usam os mesmos nomes hierárquicos da estrutura appsettings.json .NET, com cada nível separado por um sublinhado duplo (__). As chaves JavaScript mantêm os nomes folha em maiúsculas e minúsculas mostrados nas tabelas (por exemplo, azureBotOAuthConnectionName). As chaves Python estão em maiúsculas (por exemplo, AZUREBOTOAUTHCONNECTIONNAME).
Importante
Credenciais automáticas globais (AutoSignIn) e DefaultHandlerName só são compatíveis em .NET. Em JavaScript e Python, você anexa manipuladores OAuth a rotas específicas, conforme mostrado em Configuração por rota.
Configurações
Um objeto de autorização do usuário dentro de AgentApplication controla como o agente adquire tokens de usuário. No mínimo, cada manipulador nomeia a conexão OAuth de Bot do Azure usada. Os exemplos a seguir mostram a estrutura mínima em cada linguagem. As tabelas a seguir descrevem o restante das propriedades disponíveis, e as seções OBO abrangem as configurações OBOConnectionName e OBOScopes.
Em .NET, configure a autorização do usuário em AgentApplication em appsettings.json:
"AgentApplication": {
"UserAuthorization": {
"DefaultHandlerName": "{{handler-name}}",
"AutoSignIn": true | false,
"Handlers": {
"{{handler-name}}": {
"Settings": {
"AzureBotOAuthConnectionName": "{{azure-bot-connection-name}}"
}
}
}
}
}
Em JavaScript, configure a autorização do usuário com variáveis de ambiente no arquivo .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}}
Em Python, configure a autorização do usuário com variáveis de ambiente no arquivo .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}}
Propriedades de UserAuthorization
A tabela a seguir lista as propriedades de nível superior de UserAuthorization que determinam como os manipuladores são selecionados e como os tokens são adquiridos para cada atividade recebida.
| Propriedade | Obrigatório | Tipo | descrição |
|---|---|---|---|
DefaultHandlerName |
Não (recomendado) | string (cadeia de caracteres) | Somente .NET. Nome do manipulador usado quando AutoSignIn for avaliado como verdadeiro e nenhuma substituição por rota for especificada. |
AutoSignIn |
Não | bool ou delegado | Somente .NET. Quando verdadeiro (padrão), o agente tenta obter um token para cada atividade recebida. Substitua no runtime com Options.AutoSignIn para filtrar tipos de atividade. |
Handlers |
Sim (pelo menos um) | objeto (dicionário) | Mapeamento do nome do manipulador para sua configuração. Cada chave precisa ser exclusiva. |
Em .NET, para restringir a quais atividades as credenciais automáticas se aplicam, defina um predicado semelhante a: Options.AutoSignIn = (context, ct) => Task.FromResult(context.Activity.IsType(ActivityTypes.Message));. JavaScript e Python não dão suporte a credenciais automáticas globais. Em vez disso, defina as credenciais de escopo anexando nomes de manipulador específicos a rotas individuais, conforme mostrado nos exemplos por rota.
Propriedades de configurações
A tabela a seguir descreve o objeto aninhado Settings aplicado a um manipulador OAuth individual, controlando a apresentação de cartão de entrada, o comportamento de repetição, os tempos limite e a configuração opcional da troca do OBO.
| Propriedade | Obrigatório | Tipo | Descrição |
|---|---|---|---|
AzureBotOAuthConnectionName |
Sim | string (cadeia de caracteres) | Nome da conexão OAuth definido no recurso do Bot do Azure. |
OBOConnectionName |
Não (somente OBO) | string (cadeia de caracteres) | Nome de uma conexão do SDK de Agentes usada para executar uma troca de tokens em nome de outra parte. |
OBOScopes |
Não (somente OBO) | string[] | Escopos solicitados durante a troca de OBO. Se omitido com OBOConnectionName, você poderá chamar ExchangeTurnTokenAsync manualmente. |
Title |
Não | string (cadeia de caracteres) | Título do cartão de entrada personalizado. O padrão é Entrada. |
Text |
Não | string (cadeia de caracteres) | Texto do botão do cartão de entrada. O padrão é Entre. |
InvalidSignInRetryMax |
Não | int | Número máximo de tentativas permitidas quando o usuário insere um código inválido. O padrão é 2. |
InvalidSignInRetryMessage |
Não | string (cadeia de caracteres) | Mensagem mostrada após uma entrada de código inválida. O padrão é Código de entrada inválido. Digite o código de 6 dígitos. |
Timeout |
Não | int (ms) | Número de milissegundos antes de uma tentativa de entrada em andamento expirar. O padrão é 900000 (15 minutos). |
Observação
AzureBotOAuthConnectionName, OBOConnectionName, OBOScopes, Title e Text se aplicam a todas as três linguagens (usando maiúsculas e minúsculas da chave por linguagem descritas em Suporte da linguagem para OAuth).
InvalidSignInRetryMax, InvalidSignInRetryMessage e Timeout são configurações do .NET.
Qual tipo você deve usar?
Consulte a tabela a seguir para decidir qual abordagem é mais apropriada para o seu cenário.
| Opção | Use quando |
|---|---|
| Credenciais automáticas (somente .NET) | Você deseja que toda atividade recebida adquira automaticamente um token, ou deseja um subconjunto filtrado (por exemplo, somente mensagens ou tudo, exceto eventos) fornecendo um predicado para UserAuthorizationOptions.AutoSignIn. Só compatível em .NET. |
| Por rota | Somente manipuladores de rotas específicos precisam de tokens ou diferentes rotas devem usar diferentes conexões OAuth (e, portanto, diferentes tokens). Esta opção é a única em JavaScript e Python. No .NET, é aditivo com credenciais automáticas globais. Se ambos estiverem habilitados em .NET, a rodada terá acesso aos tokens de cada conexão. |
Usar o token no código (não OBO)
Esta seção mostra como recuperar e usar o token de usuário retornado diretamente pela sua conexão OAuth do Bot do Azure, sem realizar uma troca OBO (On-Behalf-Of). Em .NET, você pode usar credenciais automáticas globais ou por manipuladores de rotas. JavaScript e Python usam apenas manipuladores de rotas. Dentro do manipulador de atividade, recupere o token (GetTurnTokenAsync em .NET, authorization.getToken em JavaScript, auth.get_token em Python) o mais tarde possível, de maneira que o SDK possa atualizar o token se ele estiver próximo do vencimento. Os exemplos a seguir ilustram ambos os padrões.
Credenciais automáticas (somente .NET)
Observação
Credenciais automáticas globais e DefaultHandlerName só estão disponíveis em .NET. Para JavaScript e Python, use Configuração por rota.
Use essa configuração quando a entrada automática global deve adquirir um token para cada atividade recebida sem precisar especificar manipuladores por rota.
"AgentApplication": {
"UserAuthorization": {
"DefaultHandlerName": "auto",
"Handlers": {
"auto": {
"Settings": {
"AzureBotOAuthConnectionName": "teams_sso",
}
}
}
}
},
O código do agente seria semelhante a este:
public class MyAgent : AgentApplication
{
[MessageRoute]
public async Task OnMessageAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken cancellationToken)
{
var token = await UserAuthorization.GetTurnTokenAsync(turnContext);
// use the token
}
}
Configuração por rota
Use uma configuração por rota quando você quiser controle granular: somente as rotas que você definir explicitamente adquirem tokens. A configuração por rota tem as seguintes vantagens:
- Isso reduz a recuperação de token desnecessária.
- Ele permite que rotas diferentes segmentem conexões OAuth distintas (e, por isso, recursos ou escopos diferentes).
- Ele permite a você misturar rotas autenticadas e não autenticadas dentro do mesmo agente.
No exemplo a seguir, um único manipulador graph só é anexado à rota da mensagem.
Em .NET, as credenciais automáticas globais são desabilitadas, e o manipulador graph é anexado à rota usando autoSignInHandlers.
"AgentApplication": {
"UserAuthorization": {
"AutoSignIn": false,
"Handlers": {
"graph": {
"Settings": {
"AzureBotOAuthConnectionName": "teams_sso",
}
}
}
}
},
O código do agente seria semelhante a este:
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
}
}
Em JavaScript, passe um array de nomes de manipulador como último argumento para o registro da rota. Somente essa rota dispara credenciais para o manipulador 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
O código do agente seria semelhante a este:
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
}
}
Em Python, passe auth_handlers para o decorador da rota. Somente essa rota dispara credenciais para o manipulador GRAPH.
AGENTAPPLICATION__USERAUTHORIZATION__HANDLERS__GRAPH__SETTINGS__AZUREBOTOAUTHCONNECTIONNAME=teams_sso
O código do agente seria semelhante a este:
@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 o token durante uma rodada
Recupere o token do usuário sempre que você precisar durante uma rodada. Você pode chamá-lo várias vezes. Chame-o imediatamente antes do uso para que a lógica de atualização (se necessário) seja tratada de forma transparente.
| Linguagem | Chamada |
|---|---|
| .NET |
GetTurnTokenAsync(turnContext, handlerName) |
| JavaScript | authorization.getToken(context, handlerName) |
| Python | auth.get_token(context, handler_name) |
Usar o token no código (não OBO)
OBO (On-Behalf-Of) depende da entrada inicial do usuário fornecer um token que possa ser trocado. Isso requer que os escopos da conexão OAuth incluam um que corresponda a um escopo exposto pela API downstream (por exemplo, se o escopo exposto for defaultScopes, o escopo configurado pode ser api://botid-{{clientId}}/defaultScopes). Em seguida, o SDK de Agentes executa uma troca da MSAL (Biblioteca de Autenticação da Microsoft) usando uma conexão configurada identificada por OBOConnectionName e a lista de OBOScopes. Quando OBOConnectionName e OBOScopes estão presentes na configuração, a troca ocorre automaticamente, e você obtém o token final por meio da chamada do token padrão (GetTurnTokenAsync / getToken / get_token). Se qualquer um não for encontrado, você poderá realizar explicitamente a troca em runtime (ExchangeTurnTokenAsync em .NET, authorization.exchangeToken em JavaScript, auth.exchange_token em Python), permitindo a você resolver dinamicamente a conexão ou a lista de escopo.
OBO na configuração
Use esse padrão quando souber o recurso downstream e os escopos necessários no momento da configuração. Quando você fornece ambos OBOConnectionName e OBOScopes, o SDK executa automaticamente a troca Em nome de durante a entrada. Isso significa que chamadas subsequentes para o token padrão getter retornam diretamente o token OBO, sem necessidade de código de runtime extra.
"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"
]
}
}
},
O código do agente seria semelhante a este:
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
}
}
Em JavaScript, defina uma conexão OBO no mapa de conexões e a referencie pelo manipulador com 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
O código do agente seria semelhante a este:
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
}
}
Em Python, defina uma conexão OBO em CONNECTIONS e a referencie pelo manipulador com 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
O código do agente seria semelhante a este:
@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
Troca de OBO no runtime
Use uma troca de runtime quando você não conseguir corrigir o recurso downstream, os escopos ou a conexão na configuração. Essa situação acontece, por exemplo, quando os escopos dependem do locatário, da função do usuário ou de um sinalizador de recurso. Neste modelo, você pode configurar a conexão OBO e, em seguida, chamar o método de troca com os escopos que você decidir no momento da rodada. Você recebe um token trocado que pode aplicar imediatamente.
Chame ExchangeTurnTokenAsync com os escopos que você decidir no momento da rodada.
"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"
]
}
}
},
O código do agente seria semelhante a este:
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
}
}
Chame authorization.exchangeToken com o nome e os escopos do manipulador que você decidir no momento da rodada.
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
O código do agente seria semelhante a este:
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
}
}
Chame auth.exchange_token com o nome e os escopos do manipulador que você decidir no momento da rodada.
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
O código do agente seria semelhante a este:
@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
Configurações de OAuth regionais
Para regiões fora dos Estados Unidos, atualize o ponto de extremidade do serviço de token que seu agente usa.
A imagem a seguir mostra a configuração do .NET. Adicione-a ao appsettings.json:
"RestChannelServiceClientFactory": {
"TokenServiceEndpoint": "{{service-endpoint-uri}}"
}
Para service-endpoint-url, use o valor apropriado da tabela a seguir para bots de nuvem pública com residência de dados na região especificada.
| URI | Região |
|---|---|
https://europe.api.botframework.com |
Europa |
https://unitedstates.api.botframework.com |
Estados Unidos |
https://india.api.botframework.com |
Índia |