직접 회선 API 3.0의 인증

클라이언트는 Bot Framework 포털의 직접 회선 채널 구성 페이지에서 가져오는 비밀을 사용하거나 런타임에 가져오는 토큰을 사용하여 직접 회선 API 3.0에 대한 요청을 인증할 수 있습니다. 비밀 또는 토큰은 다음 형식을 사용하여 각 요청의 Authorization 헤더에 지정해야 합니다.

Authorization: Bearer SECRET_OR_TOKEN

비밀 및 토큰

직접 회선 비밀 은 연결된 봇에 속하는 모든 대화에 액세스하는 데 사용할 수 있는 마스터 키입니다. 토큰을 가져오는 데도 비밀을 사용할 수 있습니다. 비밀은 만료되지 않습니다.

직접 회선 토큰 은 단일 대화에 액세스하는 데 사용할 수 있는 키입니다. 토큰이 만료되지만 새로 고칠 수 있습니다.

비밀 키 또는 토큰을 사용할 시기 또는 시기를 결정하는 것은 보안 고려 사항을 기반으로 해야 합니다. 의도적으로 신중하게 수행하면 비밀 키를 노출하는 것이 허용될 수 있습니다. 사실 이 동작은 Direct Line에서 클라이언트가 합법적인지 파악할 수 있기 때문에 기본 동작입니다. 하지만 일반적으로 사용자 데이터를 유지하려는 경우 보안이 중요합니다. 자세한 내용은 보안 고려 사항 섹션 을 참조하세요.

서비스 간 애플리케이션을 만드는 경우 직접 회선 API 요청의 헤더에 Authorization 비밀을 지정하는 것이 가장 간단한 방법일 수 있습니다. 클라이언트가 웹 브라우저 또는 모바일 앱에서 실행되는 애플리케이션을 작성하는 경우 암호를 토큰(단일 대화에 대해서만 작동하고 새로 고치지 않는 한 만료됨)으로 교환하고 Direct Line API 요청 헤더에 Authorization 토큰을 지정하는 것이 좋습니다. 본인에게 가장 적합한 보안 모델을 선택합니다.

참고 항목

직접 회선 클라이언트 자격 증명은 봇의 자격 증명과 다릅니다. 이렇게 하면 키를 독립적으로 수정할 수 있으며 봇의 암호를 공개하지 않고 클라이언트 토큰을 공유할 수 있습니다.

직접 회선 비밀 가져오기

Azure Portal에서 봇에 대한 직접 회선 채널 구성 페이지를 통해 직접 회선 비밀을 가져올 수 있습니다.

Direct Line configuration

직접 회선 토큰 생성

단일 대화에 액세스하는 데 사용할 수 있는 직접 회선 토큰을 생성하려면 먼저 Azure Portal의 Direct Line 채널 구성 페이지에서 직접 회선 비밀을 가져옵니다. 그런 다음 이 요청을 실행하여 직접 회선 암호를 직접 회선 토큰으로 교환합니다.

POST https://directline.botframework.com/v3/directline/tokens/generate
Authorization: Bearer SECRET

이 요청의 Authorization 헤더에서 SECRET을 직접 회선 비밀 값으로 바꿉니다.

다음 코드 조각은 토큰 생성 요청 및 응답의 예제를 제공합니다.

Request

POST https://directline.botframework.com/v3/directline/tokens/generate
Authorization: Bearer RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0

토큰 매개 변수를 포함하는 요청 페이로드는 선택 사항이지만 권장됩니다. Direct Line 서비스에 돌려 보낼 수 있는 토큰을 생성할 때는 더 안전한 연결을 위해 다음 페이로드를 제공합니다. 이러한 값을 포함하면 Direct Line에서 사용자 ID 및 이름에 대한 추가 보안 유효성 검사를 수행하여 악의적인 클라이언트에 의한 이러한 값의 변조를 방지할 수 있습니다. 또한 이러한 값을 포함하면 Direct Line에서 대화 업데이트 작업을 보내는 기능이 향상되어 사용자가 대화에 참가하는 즉시 대화 업데이트를 생성할 수 있습니다. 이 정보가 제공되지 않으면 Direct Line에서 대화 업데이트를 보내기 전에 사용자가 콘텐츠를 보내야 합니다.

{
  "user": {
    "id": "string",
    "name": "string"
  },
  "trustedOrigins": [
    "string"
  ]
}
매개 변수 형식 Description
user.id string 선택 사항. 토큰 내에서 인코딩할 사용자의 채널별 ID입니다. Direct Line 사용자의 경우 이 값이 dl_로 시작되어야 합니다. 각 대화마다 고유한 사용자 ID를 만들 수 있고 보안을 강화하기 위해 이 ID는 추측할 수 없어야 합니다.
user.name string 선택 사항. 토큰 내에서 인코딩할 사용자의 표시 이름입니다.
trustedOrigins 문자열 배열 선택 사항. 토큰 내에 포함할 신뢰할 수 있는 do기본 목록입니다. 봇의 웹 채팅 클라이언트를 호스트할 수 있는 기본. 이는 봇에 대한 직접 회선 구성 페이지의 목록과 일치해야 합니다.

응답

요청이 성공하면 응답에는 한 대화에 유효한 값과 expires_in 토큰이 만료될 때까지의 시간(초)을 나타내는 값이 포함 token 됩니다. 토큰이 유용하게 유지되려면 토큰이 만료되기 전에 토큰 새로 고침을 수행해야 합니다.

HTTP/1.1 200 OK
[other headers]
{
  "conversationId": "abc123",
  "token": "RCurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0y8qbOF5xPGfiCpg4Fv0y8qqbOF5x8qbOF5xn",
  "expires_in": 1800
}

토큰 생성 및 대화 시작

토큰 생성 작업(POST /v3/directline/tokens/generate)은 두 작업 모두 단일 대화에 액세스하는 데 사용할 수 있는 작업을 반환 token 한다는 측면에서 대화 시작 작업(POST /v3/directline/conversations)과 유사합니다. 그러나 대화 시작 작업과 달리 토큰 생성 작업은 대화를 시작하지 않고 봇에 연결하지 않으며 스트리밍 WebSocket URL을 만들지 않습니다.

토큰을 클라이언트에 배포하고 대화를 시작하려는 경우 토큰 생성 작업을 사용합니다. 대화를 즉시 시작하려는 경우 대신 대화 시작 작업을 사용합니다.

직접 회선 토큰 새로 고침

직접 회선 토큰은 만료되지 않은 한 무제한으로 새로 고칠 수 있습니다. 만료된 토큰은 새로 고칠 수 없습니다. 직접 회선 토큰을 새로 고치려면 다음 요청을 실행합니다.

POST https://directline.botframework.com/v3/directline/tokens/refresh
Authorization: Bearer TOKEN_TO_BE_REFRESHED

이 요청의 Authorization 헤더에서 TOKEN_TO_BE_REFRESHED 새로 고치려는 직접 회선 토큰으로 바꿉다.

다음 코드 조각은 새로 고침 토큰 요청 및 응답의 예를 제공합니다.

Request

POST https://directline.botframework.com/v3/directline/tokens/refresh
Authorization: Bearer CurR_XV9ZA.cwA.BKA.iaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0y8qbOF5xPGfiCpg4Fv0y8qqbOF5x8qbOF5xn

응답

요청이 성공하면 응답에는 이전 토큰과 동일한 대화에 유효한 새 token 항목과 expires_in 새 토큰이 만료될 때까지의 시간(초)을 나타내는 값이 포함됩니다. 새 토큰이 다시 유용하려면 기본 만료되기 전에 토큰을 새로 고쳐야 합니다.

HTTP/1.1 200 OK
[other headers]
{
  "conversationId": "abc123",
  "token": "RCurR_XV9ZA.cwA.BKA.y8qbOF5xPGfiCpg4Fv0y8qqbOF5x8qbOF5xniaJrC8xpy8qbOF5xnR2vtCX7CZj0LdjAPGfiCpg4Fv0",
  "expires_in": 1800
}

Azure AI Bot Service 인증

이 섹션에 제시된 정보는 Azure AI Bot Service 문서를 통해 봇에 인증 추가 문서를 기반으로 합니다.

Azure AI Bot Service 인증을 사용하면 Microsoft Entra ID, GitHub, Uber 등과 같은 다양한 ID 공급자로부터 사용자를 인증하고 액세스 토큰을 가져올 수 있습니다. 사용자 지정 OAuth2 ID 공급자에 대한 인증을 구성할 수도 있습니다. 이 모든 기능을 통해 지원되는 모든 ID 공급자 및 채널에서 작동하는 인증 코드의 한 부분을 작성할 수 있습니다. 이러한 기능을 사용하려면 다음을 수행합니다.

  1. ID 공급자를 사용하여 애플리케이션 등록의 세부 정보를 포함하는 봇에서 정적으로 구성 settings 합니다.
  2. OAuthCard이전 단계에서 제공한 애플리케이션 정보로 지원되는 를 사용하여 사용자를 로그인합니다.
  3. Azure AI Bot Service API를 통해 액세스 토큰을 검색합니다.

보안 고려 사항

웹 채팅 Azure AI Bot Service 인증사용하는 경우 몇 가지 중요한 보안 고려 사항을 염두에 두어야 합니다.

  1. 가장. 가장은 공격자가 봇에게 공격자가 다른 사람이라고 확신하는 경우입니다. 웹 채팅 공격자는 웹 채팅 인스턴스의 사용자 ID를 변경하여 다른 사람을 가장할 수 있습니다. 가장을 방지하려면 봇 개발자가 사용자 ID를 풀 수 없도록 하는 것이 좋습니다.

    향상된 인증 옵션을 사용하도록 설정하면 Azure AI Bot Service에서 사용자 ID 변경을 추가로 감지하고 거부할 수 있습니다. 즉, 직접 회선에서 봇으로 보내는 메시지의 사용자 ID(Activity.From.Id)는 항상 웹 채팅 초기화한 사용자 ID와 동일합니다. 이 기능을 사용하려면 사용자 ID가 .로 시작해야 합니다 dl_.

    참고 항목

    토큰에 대한 비밀을 교환하는 동안 User.Id 제공되면 해당 User.Id 토큰에 포함됩니다. 직접 회선은 봇에 전송된 메시지에 활동의 From.Id 해당 ID가 있는지 확인합니다. 클라이언트가 다른 From.Id 있는 직접 회선에 메시지를 보내는 경우 메시지를 봇에 전달하기 전에 토큰의 ID로 변경됩니다. 따라서 채널 비밀이 사용자 ID로 초기화된 후에는 다른 사용자 ID를 사용할 수 없습니다.

  2. 사용자 ID. 각 사용자에게는 다음과 같은 여러 사용자 ID가 있습니다.

    1. 채널의 사용자 ID입니다.
    2. 봇이 관심 있는 ID 공급자의 사용자 ID입니다.

봇이 채널의 사용자 A에게 ID 공급자 P에 로그인하도록 요청하는 경우 로그인 프로세스는 사용자 A가 P에 로그인하는 사용자임을 확인해야 합니다. 다른 사용자 B가 로그인할 수 있는 경우 사용자 A는 봇을 통해 사용자 B의 리소스에 액세스할 수 있습니다. 웹 채팅 다음에 설명된 대로 올바른 사용자가 로그인하도록 하는 두 가지 메커니즘이 있습니다.

  1. 로그인이 끝날 때 과거에 사용자에게 임의로 생성된 6자리 코드(매직 코드)가 표시됩니다. 사용자는 로그인 프로세스를 완료하기 위해 로그인을 시작한 대화에서 이 코드를 입력해야 합니다. 이 메커니즘은 잘못된 사용자 환경을 초래하는 경향이 있습니다. 또한 여전히 피싱 공격에 취약합니다. 악의적인 사용자가 다른 사용자를 속여 로그인하고 피싱을 통해 매직 코드를 가져올 수 있습니다.

  2. 이전 방법의 문제로 인해 Azure AI Bot Service는 매직 코드의 필요성을 제거했습니다. Azure AI Bot Service는 로그인 프로세스가 웹 채팅 자체와 동일한 브라우저 세션에서만 완료될 수 있도록 보장합니다. 이 보호를 사용하도록 설정하려면 봇 개발자는 봇의 웹 채팅 클라이언트를 호스트할 수 있는 신뢰할 수 있는 do기본 목록이 포함된 직접 회선 토큰으로 웹 채팅 시작해야 합니다. 이전에는 문서화되지 않은 선택적 매개 변수를 직접 회선 토큰 API에 전달해야만 이 토큰을 얻을 수 있습니다. 현재 향상된 인증 옵션을 사용하면 Direct Line 구성 페이지에서 트러스트된 도메인(원본) 목록을 정적으로 지정할 수 있습니다.

자세한 내용은 Azure AI Bot Service를 통해 봇에 인증 추가를 참조하세요.

코드 예제

다음 .NET 컨트롤러는 향상된 인증 옵션을 사용하여 작동하며 Direct Line 토큰과 사용자 ID를 반환합니다.

public class HomeController : Controller
{
    public async Task<ActionResult> Index()
    {
        var secret = GetSecret();

        HttpClient client = new HttpClient();

        HttpRequestMessage request = new HttpRequestMessage(
            HttpMethod.Post,
            $"https://directline.botframework.com/v3/directline/tokens/generate");

        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", secret);

        var userId = $"dl_{Guid.NewGuid()}";

        request.Content = new StringContent(
            JsonConvert.SerializeObject(
                new { User = new { Id = userId } }),
                Encoding.UTF8,
                "application/json");

        var response = await client.SendAsync(request);
        string token = String.Empty;

        if (response.IsSuccessStatusCode)
        {
            var body = await response.Content.ReadAsStringAsync();
            token = JsonConvert.DeserializeObject<DirectLineToken>(body).token;
        }

        var config = new ChatConfig()
        {
            Token = token,
            UserId = userId
        };

        return View(config);
    }
}

public class DirectLineToken
{
    public string conversationId { get; set; }
    public string token { get; set; }
    public int expires_in { get; set; }
}
public class ChatConfig
{
    public string Token { get; set; }
    public string UserId { get; set; }
}

다음 JavaScript 컨트롤러는 향상된 인증 옵션을 사용하도록 설정하고 직접 회선 토큰 및 사용자 ID를 반환합니다.

var router = express.Router(); // get an instance of the express Router

// Get a directline configuration (accessed at GET /api/config)
const userId = "dl_" + createUniqueId();

router.get('/config', function(req, res) {
    const options = {
        method: 'POST',
        uri: 'https://directline.botframework.com/v3/directline/tokens/generate',
        headers: {
            'Authorization': 'Bearer ' + secret
        },
        json: {
            User: { Id: userId }
        }
    };

    request.post(options, (error, response, body) => {
        if (!error && response.statusCode < 300) {
            res.json({
                    token: body.token,
                    userId: userId
                });
        }
        else {
            res.status(500).send('Call to retrieve token from Direct Line failed');
        }
    });
});

추가 정보