Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Um agente utiliza o OAuth para ligar os utilizadores e obter tokens para recursos a jusante (como o Microsoft Graph) sem processar as próprias credenciais. O Azure Bot Service gere a troca de tokens e o agente obtém o token de utilizador resultante durante um turno.
Descrição geral
A utilização do OAuth num agente envolve três atividades:
- Configure o OAuth no Azure Bot e o registo da aplicação: crie uma ou mais ligações do OAuth no seu recurso do Azure Bot, cada uma apoiada por um registo da aplicação do Microsoft Entra ID. Adicionar autorização de utilizador utilizando credenciais de identidade federada aborda a abordagem mais comum. Outros tipos de credenciais, como segredos de cliente ou certificados, também são suportados. Para obter o conjunto completo de opções, consulte Noções básicas de autenticação do Bot Service.
- Configurar as definições correspondentes no agente: cada ligação OAuth no Azure Bot mapeia para um processador do OAuth na configuração do agente. Consulte as Definições. Para a configuração geral de agentes, consulte O que é o SDK de Agentes do Microsoft 365.
- Utilizar os tokens no código: durante um turno, obtenha o token de utilizador—ou realize uma troca On-Behalf-Of (OBO)—através da API de autorização de utilizador do agente. Consulte Utilizar o token no código (não OBO) e Utilizar o token no código (OBO).
Tenha em mente os seguintes conceitos enquanto lê o resto deste artigo:
- Um Azure Bot pode conter múltiplas ligações OAuth. Por exemplo, uma ligação para o Microsoft Graph e outra para o GitHub. Cada ligação é configurada de forma independente no Azure Bot.
- Existe uma relação 1:1 entre uma ligação OAuth no Azure Bot e um processador OAuth no agente. A definição de
AzureBotOAuthConnectionNamede um processador nomeia a ligação do Azure Bot que utiliza. Para utilizar duas ligações, defina dois processadores. - A API de autorização do utilizador do agente é a superfície que chama no código. No .NET, isto é
AgentApplication.UserAuthorization—por exemplo,GetTurnTokenAsyncpara ler um token eExchangeTurnTokenAsyncpara realizar uma troca OBO. As superfícies equivalentes sãoauthorizationno JavaScript eauthno Python.
Para exemplos práticos, consulte os exemplos de início de sessão automático e OBO para:
Suporte de linguagens para OAuth
O SDK de Agentes suporta OAuth para .NET, JavaScript e Python. Os conceitos fundamentais são os mesmos em todas as linguagens: processadores OAuth, anexação de processadores a rotas e troca OBO. Apenas o formato de configuração e os nomes das APIs dos processadores diferem:
| Idioma | Onde configura | Superfície de 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 utilizam os mesmos nomes hierárquicos da estrutura .NET appsettings.json, com cada nível separado por um duplo sublinhado (__). As chaves JavaScript mantêm os nomes das folhas em camel case mostrados nas tabelas (por exemplo, azureBotOAuthConnectionName). As chaves Python são em maiúsculas (por exemplo, AZUREBOTOAUTHCONNECTIONNAME).
Importante
O início de sessão automático global (AutoSignIn) e DefaultHandlerName são suportados apenas em .NET. Em JavaScript e Python, anexa os processadores OAuth a rotas específicas, como mostrado na Configuração por rota.
Definições
Um objeto de autorização de utilizador dentro de AgentApplication controla como o agente adquire tokens de utilizador. No mínimo, cada processador nomeia a ligação Azure Bot OAuth que utiliza. Os exemplos seguintes mostram a estrutura mínima em cada linguagem. As tabelas que se seguem descrevem o resto das propriedades disponíveis, e as secções OBO cobrem as definições OBOConnectionName e OBOScopes.
Em .NET, configure a autorização do utilizador em AgentApplication no 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 utilizador com variáveis de ambiente no ficheiro .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 utilizador com variáveis de ambiente no ficheiro .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 UserAuthorization
A tabela seguinte lista as propriedades de nível superior UserAuthorization que determinam como os processadores são selecionados e como os tokens são adquiridos para cada atividade recebida.
| Propriedade | Obrigatório | Type | Descrição |
|---|---|---|---|
DefaultHandlerName |
Não (recomendado) | cadeia (de carateres) | Apenas .NET. Nome do processador utilizado quando AutoSignIn avaliado como true e nenhuma substituição por rota é especificada. |
AutoSignIn |
Não | bool ou delegate | Apenas .NET. Quando definido como true (predefinição), o agente tenta adquirir um token para cada atividade recebida. Substitua em runtime com Options.AutoSignIn para filtrar tipos de atividade. |
Handlers |
Sim (pelo menos um) | objeto (dicionário) | Mapeamento do nome do processador para a sua configuração. Todas as chaves têm de ser exclusivas. |
Em .NET, para restringir a que atividades se aplica o início de sessão automático, defina um predicado semelhante como: Options.AutoSignIn = (context, ct) => Task.FromResult(context.Activity.IsType(ActivityTypes.Message));. O JavaScript e o Python não suportam o início de sessão automático global. Em vez disso, defina o início de sessão anexando nomes específicos de processadores a rotas individuais, como mostrado nos exemplos por rota.
Propriedades das definições
A tabela seguinte descreve o objeto aninhado Settings aplicado a um processador do OAuth individual, controlando a apresentação do cartão de início de sessão, o comportamento de repetição, os tempos limite e a configuração opcional de troca OBO.
| Propriedade | Obrigatório | Type | Descrição |
|---|---|---|---|
AzureBotOAuthConnectionName |
Sim | cadeia (de carateres) | Nome de ligação OAuth definido no recurso do Azure Bot. |
OBOConnectionName |
Não (apenas OBO) | cadeia (de carateres) | Nome de uma ligação do SDK de agentes usada para executar uma troca de token "On‑Behalf‑Of". |
OBOScopes |
Não (apenas OBO) | cadeia (de carateres)[] | Âmbitos pedidos durante a troca OBO. Se forem omitidos com OBOConnectionName, pode chamar manualmente ExchangeTurnTokenAsync. |
Title |
Não | cadeia (de carateres) | Título personalizado do cartão de início de sessão. A predefinição é Iniciar sessão. |
Text |
Não | cadeia (de carateres) | Texto do botão do cartão de início de sessão. A predefinição é Inicie sessão. |
InvalidSignInRetryMax |
Não | int | Número máximo de repetições permitidas quando o utilizador introduz um código inválido. A predefinição é 2. |
InvalidSignInRetryMessage |
Não | cadeia (de carateres) | Mensagem mostrada após uma entrada de código inválida. A predefinição é Código de início de sessão inválido. Introduza o código de 6 dígitos. |
Timeout |
Não | int (ms) | Número de milissegundos antes de uma tentativa de início de sessão em curso expirar. A predefinição é 900000 (15 minutos). |
Nota
AzureBotOAuthConnectionName, OBOConnectionName, OBOScopes, Title e Text aplicam-se a todas as três linguagens (utilizando a caixa de chaves por linguagem descrita em Suporte de linguagens para OAuth).
InvalidSignInRetryMax, InvalidSignInRetryMessage e Timeout são definições de .NET.
Que tipo deve utilizar?
Use a tabela seguinte para decidir qual a abordagem que se adequa ao seu cenário.
| Opção | Utilizar quando |
|---|---|
| Início de sessão automático (apenas .NET) | Pretende que cada atividade recebida adquira automaticamente um token, ou pretende um subconjunto filtrado (por exemplo, apenas mensagens ou tudo exceto eventos), fornecendo um predicado a UserAuthorizationOptions.AutoSignIn. Suportado apenas em .NET. |
| Por rota | Apenas os processadores de rotas específicos necessitam de tokens, ou rotas diferentes devem utilizar ligações OAuth diferentes (e, portanto, tokens diferentes). Esta opção é a única em JavaScript e Python. Em .NET, é aditivo com o início de sessão automático global. Se ambos estiverem ativados em .NET, o turno terá acesso aos tokens de cada um. |
Usar o token no código (não-OBO)
Esta secção mostra como obter e utilizar o token de utilizador devolvido diretamente pela sua ligação OAuth do Bot do Azure sem executar uma troca On‑Behalf‑Of. Em .NET, pode utilizar o início de sessão automático global ou processadores por rota. O JavaScript e o Python utilizam apenas processadores por rota. Dentro do seu processador de atividade, obtenha o token (GetTurnTokenAsync em .NET, authorization.getToken em JavaScript, auth.get_token em Python) o mais tarde possível para que o SDK possa atualizar o token se estiver perto do prazo. Os exemplos seguintes ilustram ambos os padrões.
Início de sessão automático (apenas .NET)
Nota
O início de sessão automático global e DefaultHandlerName estão disponíveis apenas em .NET. Para JavaScript e Python, utilize Configuração por rota.
Utilize esta configuração quando o início de sessão automático global deve adquirir um token para cada atividade recebida, sem necessidade de especificar processadores por rota.
"AgentApplication": {
"UserAuthorization": {
"DefaultHandlerName": "auto",
"Handlers": {
"auto": {
"Settings": {
"AzureBotOAuthConnectionName": "teams_sso",
}
}
}
}
},
O código do agente ficaria mais ou menos assim:
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
Opte por uma configuração por rota quando pretender um controlo detalhado: apenas as rotas que marcar explicitamente adquirem tokens. A configuração por rota apresenta as seguintes vantagens:
- Reduz a recuperação desnecessária de tokens.
- Permite que diferentes rotas visem ligações OAuth distintas (e, portanto, diferentes recursos ou âmbitos).
- Permite misturar rotas autenticadas e não autenticadas dentro do mesmo agente.
No exemplo a seguir, um único processador graph é anexado à rota da mensagem.
Em .NET, o início de sessão automático global está desativado e o processador graph é associado à rota utilizando autoSignInHandlers.
"AgentApplication": {
"UserAuthorization": {
"AutoSignIn": false,
"Handlers": {
"graph": {
"Settings": {
"AzureBotOAuthConnectionName": "teams_sso",
}
}
}
}
},
O código do agente ficaria mais ou menos assim:
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 uma matriz de nomes de processadores como último argumento para o registo da rota. Apenas essa rota aciona o início de sessão para o processador 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 ficaria mais ou menos assim:
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, transmita o auth_handlers ao decorador da rota. Apenas essa rota aciona o início de sessão para o processador GRAPH.
AGENTAPPLICATION__USERAUTHORIZATION__HANDLERS__GRAPH__SETTINGS__AZUREBOTOAUTHCONNECTIONNAME=teams_sso
O código do agente ficaria mais ou menos assim:
@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
Obter o token durante um turno
Obtenha o token de utilizador sempre que precisar durante um turno. É possível chamá-lo várias vezes. Chame-o imediatamente antes de o utilizar, para que a lógica de atualização (caso seja necessária) seja processada de forma transparente.
| Idioma | Ligar para |
|---|---|
| .NET |
GetTurnTokenAsync(turnContext, handlerName) |
| JavaScript | authorization.getToken(context, handlerName) |
| Python | auth.get_token(context, handler_name) |
Usar o token no código (OBO)
O On-Behalf-Of (OBO) depende do início de sessão inicial do utilizador devolvendo um token permutável. Isso requer que os âmbitos da ligação OAuth incluam um que corresponda a um âmbito exposto pela API a jusante (por exemplo, se o âmbito exposto for defaultScopes, o âmbito configurado pode ser api://botid-{{clientId}}/defaultScopes). O SDK de Agentes processa então uma troca da Biblioteca de Autenticação da Microsoft (MSAL) utilizando uma ligação configurada identificada por OBOConnectionName e a lista de OBOScopes. Quanto tanto o OBOConnectionName como o OBOScopes estão presentes na configuração, a troca ocorre automaticamente e o token final é obtido através da chamada de token padrão (GetTurnTokenAsync / getToken / get_token). Se algum deles estiver em falta, pode realizar a troca explicitamente em runtime (ExchangeTurnTokenAsync em .NET, authorization.exchangeToken em JavaScript, auth.exchange_token em Python), permitindo resolver dinamicamente a lista de ligação ou de âmbito.
OBO em configuração
Use esse padrão quando conhecer o recurso a jusante e os âmbitos necessários no momento da configuração. Quando fornece ambos OBOConnectionName e OBOScopes, o SDK executa automaticamente a troca On‑Behalf‑Of durante o início de sessão. Isto significa que chamadas subsequentes ao getter de token padrão devolvem diretamente o token OBO, sem necessidade de um código adicional em 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"
]
}
}
},
O código do agente ficaria mais ou menos assim:
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 ligação OBO no mapa de ligações e faça referência à mesma a partir do processador 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 ficaria mais ou menos assim:
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 ligação OBO em CONNECTIONS e faça referência à mesma a partir do processador 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 ficaria mais ou menos assim:
@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 OBO em runtime
Utilize uma troca em runtime quando não for possível corrigir o recurso a jusante, os âmbitos ou a ligação na configuração. Esta situação acontece, por exemplo, quando os âmbitos dependem do inquilino, da função do utilizador ou de um sinalizador de funcionalidade. Neste modelo, configura opcionalmente a ligação OBO e, em seguida, chama o método de troca com os âmbitos que decide no momento do turno. Recebe um token trocado que pode aplicar imediatamente.
Chame ExchangeTurnTokenAsync com os âmbitos que decidir no momento do 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"
]
}
}
},
O código do agente ficaria mais ou menos assim:
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 do processador e os âmbitos que decidir no momento do 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
O código do agente ficaria mais ou menos assim:
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 os âmbitos que decidir no momento do turno e o nome do processador.
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 ficaria mais ou menos assim:
@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
Definições regionais OAuth
Para regiões fora dos EUA, atualize o ponto final de serviço de tokens que o seu agente utiliza.
O exemplo seguinte mostra a configuração do .NET. Adicione-o a appsettings.json:
"RestChannelServiceClientFactory": {
"TokenServiceEndpoint": "{{service-endpoint-uri}}"
}
Para service-endpoint-url, use o valor apropriado da tabela seguinte para bots de cloud pública com residência dos dados na região especificada.
| URL | País/Região |
|---|---|
https://europe.api.botframework.com |
Europa |
https://unitedstates.api.botframework.com |
Estados Unidos |
https://india.api.botframework.com |
Índia |