.NET エージェントの OAuth は、最初に Azure Bot リソースと対応するアプリの登録にプロビジョニングされます。 エージェント ランタイムは、 AgentApplication 自動サインイン機能を使用してユーザー トークンを取得して更新します。 自動サインインは、グローバル (すべてのアクティビティの種類) または選択的に実行できるため、特定のルートまたはアクティビティの種類のみがトークンを要求できます。
複数の OAuth ハンドラーを構成に登録して特定のルートに割り当てたり、どこでも使用される 1 つの既定のハンドラーを宣言したりできます。 各ハンドラーは、Azure 側が構成されている場合、オプションで代理 (OBO) のやり取りを実行できます。 クイック スタートについては、 AutoSignIn サンプルを参照するか、ここに示す構成を既存のエージェントに変更します。
以降のセクションでは、ターン中に UserAuthorizationを構成し、グローバルアプローチとルートごとのアプローチを決定し、トークン (標準と OBO) を取得する方法について説明します。 米国以外のデプロイに関するリージョン ガイダンスも提供されています。
.NET エージェントは、appsettings または Program.cs のコードを使用して構成されます。 このドキュメントでは、appsettings の使用について詳しく説明します。
設定
UserAuthorization内のAgentApplication オブジェクトは、ユーザー トークンの取得方法を制御します。 次の JSON は、階層構造の後に、 UserAuthorization と入れ子になった 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}}
}
}
}
}
}
UserAuthorization プロパティ
次の表に、ハンドラーの選択方法と、受信アクティビティごとにトークンを取得する方法を決定する最上位の UserAuthorization プロパティを示します。
| プロパティ | 必須 | タイプ | Description |
|---|---|---|---|
DefaultHandlerName |
いいえ (推奨) | 文字列 |
AutoSignInが true と評価され、ルートごとのオーバーライドが指定されていない場合に使用されるハンドラーの名前。 |
AutoSignIn |
いいえ | bool またはデリゲート | true (既定値) の場合、エージェントは受信アクティビティごとにトークンの取得を試みます。は、アクティビティの種類をフィルター処理する Options.AutoSignIn を使用して実行時にオーバーライドできます。 |
Handlers |
はい (少なくとも 1 つ) | オブジェクト (ディクショナリ) | ハンドラー名とその構成のマッピング。 各キーは一意である必要があります。 |
自動サインインが適用されるアクティビティを制限するには、次のような述語を設定します: Options.AutoSignIn = (context, ct) => Task.FromResult(context.Activity.IsType(ActivityTypes.Message));。
設定プロパティ
次の表では、個々の OAuth ハンドラーに適用される入れ子になった Settings オブジェクトについて説明し、サインイン カードの表示、再試行動作、タイムアウト、およびオプションの OBO 交換構成を制御します。
| プロパティ | 必須 | タイプ | Description |
|---|---|---|---|
AzureBotOAuthConnectionName |
イエス | 文字列 | Azure Bot リソースで定義されている OAuth 接続名。 |
OBOConnectionName |
いいえ (OBO のみ) | 文字列 | On‑Behalf‑Of トークン交換の実行に使用される Agents SDK 接続の名称。 |
OBOScopes |
いいえ (OBO のみ) | string[] | OBO 交換中に要求されたスコープ。 OBOConnectionName で省略した場合は、 ExchangeTurnTokenAsync を手動で呼び出すことができます。 |
Title |
いいえ | 文字列 | カスタムサインインカードのタイトルは、既定で[サインイン]に設定されます。 |
Text |
いいえ | 文字列 | サインイン カード ボタンのテキスト。既定値は [サインインしてください] です。 |
InvalidSignInRetryMax |
いいえ | 整数 (int) | ユーザーが無効なコードを入力したときに許容される再試行の最大数。既定値は 2 です。 |
InvalidSignInRetryMessage |
いいえ | 文字列 | 無効なコード エントリの後に表示されるメッセージ。の既定値は 無効なサインイン コードです。6 桁のコードを入力してください。 |
Timeout |
いいえ | int (ms) | 進行中のサインイン試行が期限切れになるまでのミリ秒数。 既定値は 900000 (15 分) です。 |
どのような種類を使用しますか?
次の表を使用して、シナリオに適したアプローチを決定します。
| 選択肢 | 次の場合に使用します。 |
|---|---|
| 自動サインイン | すべての受信アクティビティでトークンを自動的に取得する場合や、 UserAuthorizationOptions.AutoSignInする述語を指定してフィルター処理されたサブセット (メッセージのみ、イベントを除くすべてなど) が必要です。 |
| ルートごと | 特定のルート ハンドラーのみがトークンを必要とするか、異なるルートで異なる OAuth 接続 (したがって異なるトークン) を使用する必要があります。 これは、グローバル自動サインインの追加機能です。 両方が有効になっている場合、ターンはそれぞれのトークンにアクセスできます。 |
コードでトークンを使用する (OBO 以外)
このセクションでは、On-Behalf-Of 交換を実行せずに、Azure Bot OAuth 接続によって直接返されるユーザー トークンを取得して使用する方法について説明します。 最初に、グローバル自動サインインハンドラーとルートごとのハンドラーのどちらを使用するかを決定します。その後、アクティビティ ハンドラー内でできるだけ遅く UserAuthorization.GetTurnTokenAsync 呼び出して、期限が近づいている場合に SDK がトークンを更新できるようにします。 次の例は、両方のパターンを示しています。
自動サインインのみの構成
この構成は、グローバル自動サインインが、ルートごとのハンドラーを指定することなく、すべての受信アクティビティのトークンを取得する必要がある場合に使用します。
"AgentApplication": {
"UserAuthorization": {
"DefaultHandlerName": "auto",
"Handlers": {
"auto": {
"Settings": {
"AzureBotOAuthConnectionName": "teams_sso",
}
}
}
}
},
エージェント コードは次のようになります。
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
}
}
ルート単位のみの構成
きめ細かい制御が必要な場合は、ルートごとの構成を使用します。トークンの取得を明示的にマークしたルートのみ。 ルートごとの構成では、不要なトークンの取得が減り、異なるルートが個別の OAuth 接続 (および異なるリソースまたはスコープ) を対象とすることができ、同じエージェント内で認証されたルートと認証されていないルートを混在させることが可能になります。 次の例では、グローバル自動サインインが無効になり、1 つの messageOauth ハンドラーがメッセージ ルートにのみアタッチされます。
"AgentApplication": {
"UserAuthorization": {
"AutoSignIn": false,
"Handlers": {
"messageOauth": {
"Settings": {
"AzureBotOAuthConnectionName": "teams_sso",
}
}
}
}
},
エージェント コードは次のようになります。
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
}
}
GetTurnTokenAsync を使用する
ターン中にユーザー トークンが必要な場合は常に GetTurnTokenAsync を呼び出します。 複数回呼び出すことができます。 更新ロジック (必要な場合) が透過的に処理されるように、使用する直前に呼び出します。
コードでトークンを使用する (OBO)
オンビヘイーフオブ (OBO) は、交換可能なトークンを返す初回ユーザーサインインに依存します。 そのためには、OAuth 接続のスコープに、ダウンストリーム API によって公開されるスコープに対応するスコープを含める必要があります (たとえば、公開されているスコープが defaultScopes場合、構成されたスコープが api://botid-{{clientId}}/defaultScopesされる可能性があります)。 その後、Agents SDK は、 OBOConnectionName によって識別される構成済みの接続と OBOScopesの一覧を使用して、Microsoft Authentication Library (MSAL) 交換を実行します。 構成に OBOConnectionName と OBOScopes の両方が存在する場合、交換は自動的に行われ、 GetTurnTokenAsyncを使用して最終的なトークンを取得します。 いずれかが見つからない場合は、 ExchangeTurnTokenAsyncを使用して実行時に明示的に交換を実行し、接続またはスコープ リストを動的に解決できます。
構成内の OBO
このパターンは、構成時に必要なダウンストリーム リソースとスコープがわかっている場合に使用します。
OBOConnectionNameとOBOScopesの両方を指定すると、SDK はサインイン時に自動的に On-Behalf-Of 交換を実行します。 つまり、後続の呼び出し GetTurnTokenAsync 、追加のランタイム コードを必要とせず、OBO トークンを直接返します。
"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"
]
}
}
},
エージェント コードは次のようになります。
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
ダウンストリーム リソース、スコープ、または使用する必要がある接続を構成で固定できない場合 (たとえば、スコープがテナント、ユーザー ロール、機能フラグに依存する場合など) は、ランタイム交換を使用します。 このモデルでは、(必要に応じて) OBOConnectionNameを構成し、ターンタイムに決定したスコープで ExchangeTurnTokenAsync を呼び出し、すぐに適用できる交換トークンを受け取ります。
"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"
]
}
}
},
エージェント コードは次のようになります。
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
}
}
リージョン OAuth の設定
米国以外のリージョンの場合は、エージェントによって使用されるトークン サービス エンドポイントを更新する必要があります。
次を appsettings.jsonに追加します。
"RestChannelServiceClientFactory": {
"TokenServiceEndpoint": "{{service-endpoint-uri}}"
}
service-endpoint-urlの場合は、指定したリージョンのデータ所在地を持つパブリック クラウド ボットに対して、次の表の適切な値を使用します。
| URI | リージョン |
|---|---|
https://europe.api.botframework.com |
ヨーロッパ |
https://unitedstates.api.botframework.com |
米国 |
https://india.api.botframework.com |
インド |