Bagikan melalui


Proksi Penyedia Identitas

Dokumen ini menjelaskan cara membuat proksi untuk berinteraksi dengan penyedia identitas kustom atau tingkat lanjut yang menggunakan protokol OAuth2.

Bot Framework memungkinkan pengguna untuk masuk menggunakan berbagai idP yang menggunakan protokol OAuth2. Namun, penyedia identitas dapat menyimpang dari protokol OAuth2 inti, dengan menawarkan kemampuan yang lebih canggih, atau opsi masuk alternatif. Dalam kasus ini, Anda mungkin tidak menemukan konfigurasi pengaturan koneksi yang sesuai yang berfungsi untuk Anda. Solusi yang mungkin adalah melakukan hal berikut:

  1. Tulis proksi penyedia OAuth2 yang berada di antara layanan token Bot Framework dan penyedia identitas yang lebih disesuaikan atau canggih .
  2. Konfigurasikan pengaturan koneksi untuk memanggil proksi ini, dan minta proksi ini melakukan panggilan ke penyedia identitas kustom atau tingkat lanjut. Proksi juga dapat memetakan atau mengubah respons agar sesuai dengan apa yang diharapkan layanan token Kerangka Kerja Bot.

Layanan Proksi OAuth2

Untuk membangun Layanan Proksi OAuth2, Anda perlu menerapkan layanan REST dengan dua API OAuth2: satu untuk otorisasi dan satu untuk mengambil token. Di bawah ini, Anda akan menemukan contoh C# dari masing-masing metode ini dan apa yang dapat Anda lakukan dalam metode ini untuk memanggil penyedia identitas kustom atau tingkat lanjut.

Mengotorisasi API

API otorisasi adalah HTTP GET yang mengotorisasi pemanggil, menghasilkan properti kode, dan mengalihkan ke URI pengalihan.

[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 adalah HTTP POST yang dipanggil oleh layanan token Bot Framework. Layanan token Kerangka Kerja Bot akan mengirim client_id dan client_secret dalam isi permintaan. Nilai-nilai ini harus divalidasi dan/atau diteruskan ke IdP kustom atau tingkat lanjut. Respons terhadap panggilan ini adalah objek JSON yang berisi nilai dan kedaluwarsa access_token token (semua nilai lainnya diabaikan). Jika IdP Anda mengembalikan id_token atau beberapa nilai lain yang ingin Anda kembalikan, Anda hanya perlu memetakannya ke access_token properti respons Anda sebelum kembali.

[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'");
    }
}

Konfigurasi Pengaturan Koneksi Proksi

Setelah Layanan Proksi OAuth2 berjalan, Anda dapat membuat Pengaturan Koneksi Penyedia Layanan OAuth di sumber daya Azure AI Bot Service Anda. Ikuti langkah-langkah yang dijelaskan di bawah ini.

  1. Berikan nama ke pengaturan koneksi.
  2. Pilih penyedia layanan Generic Oauth 2 .
  3. Masukkan Id Klien dan Rahasia klien untuk koneksi tersebut. Nilai-nilai ini mungkin disediakan oleh idP tingkat lanjut atau kustom Anda, atau ini bisa spesifik hanya untuk proksi Anda jika penyedia identitas yang Anda gunakan tidak menggunakan id klien dan rahasia.
  4. Untuk URL Otorisasi, Anda harus menyalin alamat REST API otorisasi Anda, misalnya https://proxy.com/api/oauth/authorize.
  5. Untuk URL Token dan Refresh, Anda harus menyalin alamat REST API token Anda, misalnya https://proxy.com/api/oauth/token. URL Pertukaran Token hanya berlaku untuk penyedia berbasis AAD sehingga dapat diabaikan.
  6. Terakhir, tambahkan cakupan apa pun yang sesuai.

OAuthController untuk aplikasi web ASP.NET

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; }
    }
}