Proxy provider di identità
Questo documento illustra come creare un proxy per interagire con provider di identità personalizzati o avanzati che usano il protocollo OAuth2.
Bot Framework consente agli utenti di accedere usando vari provider di identità che usano il protocollo OAuth2. Tuttavia, i provider di identità possono deviare dal protocollo OAuth2 di base, offrendo funzionalità più avanzate o opzioni di accesso alternative. In questi casi, potrebbe non essere disponibile una configurazione appropriata dell'impostazione di connessione che funziona per l'utente . Una possibile soluzione consiste nell'eseguire le operazioni seguenti:
- Scrivere un proxy provider OAuth2 che si trova tra il servizio token bot Framework e il provider di identità più personalizzato o avanzato .
- Configurare l'impostazione di connessione per chiamare questo proxy e avere questo proxy effettua le chiamate al provider di identità personalizzato o avanzato. Il proxy può anche eseguire il mapping o la trasformazione delle risposte per renderle conformi a quanto previsto dal servizio token di Bot Framework.
Servizio proxy OAuth2
Per creare un servizio proxy OAuth2, è necessario implementare un servizio REST con due API OAuth2: una per l'autorizzazione e una per il recupero di un token. Di seguito è riportato un esempio C# di ognuno di questi metodi e ciò che è possibile eseguire in questi metodi per chiamare un provider di identità personalizzato o avanzato.
Autorizzare l'API
L'API di autorizzazione è un GET HTTP che autorizza il chiamante, genera una proprietà di codice e reindirizza all'URI di reindirizzamento.
[HttpGet("authorize")]
public ActionResult Authorize(
string response_type,
string client_id,
string state,
string redirect_uri,
string scope = null)
{
// validate parameters
if (string.IsNullOrEmpty(state))
{
return BadRequest("Authorize request missing parameter 'state'");
}
if (string.IsNullOrEmpty(redirect_uri))
{
return BadRequest("Authorize request missing parameter 'redirect_uri'");
}
// redirect to an external identity provider,
// or for this sample, generate a code and token pair and redirect to the redirect_uri
var code = Guid.NewGuid().ToString("n");
var token = Guid.NewGuid().ToString("n");
_tokens.AddOrUpdate(code, token, (c, t) => token);
return Redirect($"{redirect_uri}?code={code}&state={state}");
}
API dei token
L'API token è un POST HTTP chiamato dal servizio token di Bot Framework. Il servizio token bot Framework invierà e client_id
client_secret
nel corpo della richiesta. Questi valori devono essere convalidati e/o passati insieme al provider di identità personalizzato o avanzato.
La risposta a questa chiamata è un oggetto JSON contenente il access_token
valore e la scadenza del token (tutti gli altri valori vengono ignorati). Se il provider di identità restituisce un id_token
valore o un altro valore che si vuole restituire, è sufficiente eseguirne il mapping alla access_token
proprietà della risposta prima di restituire.
[HttpPost("token")]
public async Task<ActionResult> Token()
{
string body;
using (var reader = new StreamReader(Request.Body))
{
body = await reader.ReadToEndAsync();
}
if (string.IsNullOrEmpty(body))
{
return BadRequest("Token request missing body");
}
var parameters = HttpUtility.ParseQueryString(body);
string authorizationCode = parameters["code"];
string grantType = parameters["grant_type"];
string clientId = parameters["client_id"];
string clientSecret = parameters["client_secret"];
string redirectUri= parameters["redirect_uri"];
// Validate any of these parameters here, or call out to an external identity provider with them
if (_tokens.TryRemove(authorizationCode, out string token))
{
return Ok(new TokenResponse()
{
AccessToken = token,
ExpiresIn = 3600,
TokenType = "custom",
});
}
else
{
return BadRequest("Token request body did not contain parameter 'code'");
}
}
Configurazione delle impostazioni di connessione proxy
Dopo aver eseguito il servizio proxy OAuth2, è possibile creare un'impostazione di connessione del provider di servizi OAuth nella risorsa di servizio Bot di Intelligenza artificiale di Azure. Seguire i passaggi descritti di seguito.
- Assegnare un nome all'impostazione di connessione.
- Selezionare il provider di servizi Oauth 2 generico .
- Immettere un ID client e un segreto client per la connessione. Questi valori potrebbero essere forniti dal provider di identità avanzato o personalizzato oppure potrebbero essere specifici solo per il proxy se il provider di identità in uso non usa l'ID client e il segreto.
- Per l'URL di autorizzazione, è necessario copiare l'indirizzo dell'API REST di autorizzazione, ad esempio
https://proxy.com/api/oauth/authorize
. - Per l'URL token e aggiorna, è necessario copiare l'indirizzo dell'API REST del token, ad esempio
https://proxy.com/api/oauth/token
. L'URL di Exchange token è valido solo per i provider basati su AAD e quindi può essere ignorato. - Aggiungere infine tutti gli ambiti appropriati.
OAuthController per ASP.NET'app Web
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Threading.Tasks;
using System.Web;
namespace CustomOAuthProvider.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class OAuthController : ControllerBase
{
ConcurrentDictionary<string, string> _tokens;
public OAuthController(ConcurrentDictionary<string, string> tokens)
{
_tokens = tokens;
}
[HttpGet("authorize")]
public ActionResult Authorize(
string response_type,
string client_id,
string state,
string redirect_uri,
string scope = null)
{
if (string.IsNullOrEmpty(state))
{
return BadRequest("Authorize request missing parameter 'state'");
}
if (string.IsNullOrEmpty(redirect_uri))
{
return BadRequest("Authorize request missing parameter 'redirect_uri'");
}
// reidrect to an external identity provider,
// or for this sample, generte a code and token pair and redirect to the redirect_uri
var code = Guid.NewGuid().ToString("n");
var token = Guid.NewGuid().ToString("n");
_tokens.AddOrUpdate(code, token, (c, t) => token);
return Redirect($"{redirect_uri}?code={code}&state={state}");
}
[HttpPost("token")]
public async Task<ActionResult> Token()
{
string body;
using (var reader = new StreamReader(Request.Body))
{
body = await reader.ReadToEndAsync();
}
if (string.IsNullOrEmpty(body))
{
return BadRequest("Token request missing body");
}
var parameters = HttpUtility.ParseQueryString(body);
string authorizationCode = parameters["code"];
string grantType = parameters["grant_type"];
string clientId = parameters["client_id"];
string clientSecret = parameters["client_secret"];
string redirectUri= parameters["redirect_uri"];
// Validate any of these parameters here, or call out to an external identity provider with them
if (_tokens.TryRemove(authorizationCode, out string token))
{
return Ok(new TokenResponse()
{
AccessToken = token,
ExpiresIn = 3600,
TokenType = "custom",
});
}
else
{
return BadRequest("Token request body did not contain parameter 'code'");
}
}
}
public class TokenResponse
{
[JsonProperty("access_token")]
public string AccessToken { get; set; }
[JsonProperty("id_token")]
public string IdToken { get; set; }
[JsonProperty("token_type")]
public string TokenType { get; set; }
[JsonProperty("expires_in")]
public int ExpiresIn { get; set; }
[JsonProperty("refresh_token")]
public string RefreshToken { get; set; }
[JsonProperty("scope")]
public string Scope { get; set; }
}
}