Proxy voor id-providers
In dit document wordt uitgelegd hoe u een proxy maakt voor interactie met aangepaste of geavanceerde id-providers die gebruikmaken van het OAuth2-protocol.
Met Bot Framework kunnen gebruikers zich aanmelden met behulp van verschillende id-providers die gebruikmaken van het OAuth2-protocol. Id-providers kunnen echter afwijken van het OAuth2-kernprotocol door meer geavanceerde mogelijkheden of alternatieve aanmeldingsopties te bieden. In dergelijke gevallen vindt u mogelijk geen geschikte configuratie van de verbindingsinstellingen die voor u werkt. Een mogelijke oplossing is om het volgende te doen:
- Schrijf een OAuth2-providerproxy tussen de Bot Framework-tokenservice en de meer aangepaste of geavanceerde id-provider.
- Configureer de verbindingsinstelling om deze proxy aan te roepen en laat deze proxy de aanroepen naar de aangepaste of geavanceerde id-provider uitvoeren. De proxy kan ook antwoorden toewijzen of transformeren om ze te laten voldoen aan wat de Bot Framework-tokenservice verwacht.
OAuth2-proxyservice
Als u een OAuth2-proxyservice wilt bouwen, moet u een REST-service implementeren met twee OAuth2-API's: één voor autorisatie en één voor het ophalen van een token. Hieronder vindt u een C#-voorbeeld van elk van deze methoden en wat u met deze methoden kunt doen om een aangepaste of geavanceerde id-provider aan te roepen.
API autoriseren
De autorisatie-API is een HTTP GET die de aanroeper autoriseert, een code-eigenschap genereert en omleidt naar de omleidings-URI.
[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}");
}
Token-API
De token-API is een HTTP POST die wordt aangeroepen door de Bot Framework-tokenservice. De Bot Framework-tokenservice verzendt de client_id
en client_secret
in de hoofdtekst van de aanvraag. Deze waarden moeten worden gevalideerd en/of doorgegeven aan de aangepaste of geavanceerde id-provider.
Het antwoord op deze aanroep is een JSON-object dat de access_token
verloopwaarde en van het token bevat (alle andere waarden worden genegeerd). Als uw id-provider een id_token
of een andere waarde retourneert die u in plaats daarvan wilt retourneren, hoeft u deze alleen maar toe te wijzen aan de access_token
eigenschap van uw antwoord voordat u terugkeert.
[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'");
}
}
Configuratie van proxyverbindingsinstelling
Zodra uw OAuth2-proxyservice wordt uitgevoerd, kunt u een verbindingsinstelling voor de OAuth-serviceprovider maken in uw Azure AI Bot Service-resource. Volg de onderstaande stappen.
- Geef een naam op voor de verbindingsinstelling.
- Selecteer de algemene Oauth 2-serviceprovider .
- Voer een client-id en clientgeheim in voor de verbinding. Deze waarden kunnen worden opgegeven door uw geavanceerde of aangepaste id-provider, of deze kunnen specifiek zijn voor uw proxy als de id-provider die u gebruikt geen client-id en geheim gebruikt.
- Voor de autorisatie-URL moet u het adres van uw autorisatie-REST API kopiëren, bijvoorbeeld
https://proxy.com/api/oauth/authorize
. - Voor token en vernieuwings-URL moet u het adres van uw token REST API kopiëren, bijvoorbeeld
https://proxy.com/api/oauth/token
. De Token Exchange-URL is alleen geldig voor AAD-providers en kan dus worden genegeerd. - Voeg ten slotte eventuele bereiken toe die geschikt zijn.
OAuthController voor ASP.NET web-app
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; }
}
}