Identitetsproviderproxy
Det här dokumentet beskriver hur du skapar en proxy för att interagera med anpassade eller avancerade identitetsprovidrar som använder OAuth2-protokollet.
Med Bot Framework kan användare logga in med hjälp av olika identitetsprovidrar som använder OAuth2-protokollet. Identitetsprovidrar kan dock avvika från OAuth2-kärnprotokollet genom att erbjuda mer avancerade funktioner eller alternativa inloggningsalternativ. I dessa fall kanske du inte hittar någon lämplig konfiguration för anslutningsinställningar som fungerar för dig. En möjlig lösning är att göra följande:
- Skriv en OAuth2-providerproxy som finns mellan Bot Framework-tokentjänsten och den mer anpassade eller avancerade identitetsprovidern .
- Konfigurera anslutningsinställningen för att anropa den här proxyn och låt proxyn göra anropen till den anpassade eller avancerade identitetsprovidern. Proxyn kan också mappa eller transformera svar så att de överensstämmer med vad Bot Framework-tokentjänsten förväntar sig.
OAuth2 Proxy Service
Om du vill skapa en OAuth2-proxytjänst måste du implementera en REST-tjänst med två OAuth2-API:er: en för auktorisering och en för att hämta en token. Nedan hittar du ett C#-exempel på var och en av dessa metoder och vad du kan göra i dessa metoder för att anropa en anpassad eller avancerad identitetsprovider.
Auktorisera API
Auktorisera API:et är en HTTP GET som auktoriserar anroparen, genererar en kodegenskap och omdirigerar till omdirigerings-URI:n.
[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
Token-API:et är en HTTP POST som anropas av Bot Framework-tokentjänsten. Bot Framework-tokentjänsten skickar client_id
och client_secret
i begärans brödtext. Dessa värden ska verifieras och/eller skickas till den anpassade eller avancerade identitetsprovidern.
Svaret på det här anropet är ett JSON-objekt som innehåller access_token
och förfallovärdet för token (alla andra värden ignoreras). Om din identitetsprovider returnerar ett id_token
eller något annat värde som du vill returnera i stället behöver du bara mappa det till egenskapen för access_token
ditt svar innan du returnerar.
[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'");
}
}
Konfiguration av proxyanslutningsinställning
När du har din OAuth2-proxytjänst igång kan du skapa en anslutningsinställning för OAuth-tjänstprovidern på din Azure AI-Bot Service resurs. Följ stegen som beskrivs nedan.
- Ge anslutningsinställningen ett namn.
- Välj den allmänna Oauth 2-tjänstleverantören .
- Ange ett klient-ID och en klienthemlighet för anslutningen. Dessa värden kan tillhandahållas av din avancerade eller anpassade identitetsprovider, eller så kan de vara specifika bara för proxyn om identitetsprovidern du använder inte använder klient-ID och hemlighet.
- För auktoriserings-URL:en bör du kopiera adressen till rest-API:et för auktorisering, till exempel
https://proxy.com/api/oauth/authorize
. - För token- och uppdaterings-URL:en bör du kopiera adressen till din token REST API, till exempel
https://proxy.com/api/oauth/token
. Token Exchange-URL:en är endast giltig för AAD-baserade providers och kan därför ignoreras. - Lägg slutligen till eventuella omfång som är lämpliga.
OAuthController för ASP.NET webbapp
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; }
}
}