자습서: Azure Functions를 사용하여 Azure SignalR Service 인증

이 단계별 자습서에서는 다음 기술을 사용하여 인증 및 프라이빗 메시징이 포함된 채팅방을 빌드합니다.

  • Azure Functions: 사용자를 인증하고 채팅 메시지를 보내기 위한 백 엔드 API입니다.
  • Azure SignalR Service: 연결된 채팅 클라이언트에 새 메시지를 브로드캐스트하는 서비스입니다.
  • Azure Storage: Azure Functions에 필요한 스토리지 서비스입니다.
  • Azure App Service: 사용자 인증을 제공하는 서비스입니다.

참고 항목

이 문서에 언급된 코드는 GitHub에서 가져올 수 있습니다.

필수 조건

문제가 있나요? 알려주세요.

Azure에서 필수 리소스 만들기

Azure SignalR Service 리소스 만들기

애플리케이션은 Azure SignalR Service 인스턴스에 액세스합니다. Azure Portal을 사용하여 Azure SignalR Service 인스턴스를 만들려면 다음 단계를 따릅니다.

  1. Azure Portal에서 리소스 만들기(+) 단추를 선택합니다.

  2. SignalR Service를 검색하여 선택합니다.

  3. 만들기를 실행합니다.

  4. 다음 정보를 입력합니다.

    속성
    리소스 그룹 고유한 이름으로 새 리소스 그룹을 만듭니다.
    리소스 이름 Azure SignalR Service 인스턴스의 고유 이름을 입력합니다.
    지역 가까운 지역을 선택합니다.
    가격 책정 계층 무료를 선택합니다.
    서비스 모드 서버리스를 선택합니다.
  5. 검토 + 생성를 선택합니다.

  6. 만들기를 선택합니다.

문제가 있나요? 알려주세요.

Azure 함수 앱 및 Azure Storage 계정 만들기

  1. Azure Portal 홈페이지에서 리소스 만들기(+)를 선택합니다.

  2. 함수 앱을 검색하여 선택합니다.

  3. 만들기를 실행합니다.

  4. 다음 정보를 입력합니다.

    속성
    리소스 그룹 Azure SignalR Service 인스턴스와 동일한 리소스 그룹을 사용합니다.
    함수 앱 이름 함수 앱의 고유한 이름을 입력합니다.
    런타임 스택 Node.js를 선택합니다.
    지역 가까운 지역을 선택합니다.
  5. 기본적으로 새 Azure Storage 계정은 함수 앱과 함께 동일한 리소스 그룹에 만들어집니다. 함수 앱에서 다른 스토리지 계정을 사용하려면 호스팅 탭으로 전환하여 계정을 선택합니다.

  6. 검토 + 만들기를 선택한 후 만들기를 선택합니다.

로컬에서 Azure Functions 프로젝트 만들기

함수 앱 초기화

  1. 명령줄에서 프로젝트의 루트 폴더를 만들고 폴더로 변경합니다.

  2. 터미널에서 다음 명령을 실행하여 새 JavaScript 함수 프로젝트를 만듭니다.

func init --worker-runtime node --language javascript --name my-app --model V4

기본적으로 생성된 프로젝트에는 SignalR 확장을 포함하는 확장 번들을 포함하는 host.json 파일이 포함되어 있습니다. 확장 번들에 대한 자세한 내용은 Azure Functions 바인딩 확장 등록을 참조하세요.

애플리케이션 설정 구성

Azure Functions 런타임을 로컬로 실행하고 디버그하면 함수 앱은 local.settings.json에서 애플리케이션 설정을 읽습니다. Azure SignalR Service 인스턴스의 연결 문자열과 이전에 만든 스토리지 계정으로 이 파일을 업데이트합니다.

local.settings.json의 콘텐츠를 다음 코드로 바꿉니다.

{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "AzureWebJobsStorage": "<your-storage-account-connection-string>",
    "AzureSignalRConnectionString": "<your-Azure-SignalR-connection-string>"
  }
}

위의 코드에서

  • Azure SignalR Service 연결 문자열을 AzureSignalRConnectionString 설정에 입력합니다.

    문자열을 가져오려면 Azure Portal에서 Azure SignalR Service 인스턴스로 이동합니다. 설정 섹션에서 설정을 찾습니다. 연결 문자열 오른쪽에 있는 복사 단추를 선택하여 클립보드에 복사합니다. 기본 또는 보조 연결 문자열을 사용할 수 있습니다.

  • 스토리지 계정 연결 문자열을 AzureWebJobsStorage 설정에 입력합니다.

    문자열을 가져오려면 Azure Portal에서 스토리지 계정으로 이동합니다. 보안 + 네트워킹 섹션에서 액세스 키 설정을 찾습니다. 연결 문자열 오른쪽에 있는 복사 단추를 선택하여 클립보드에 복사합니다. 기본 또는 보조 연결 문자열을 사용할 수 있습니다.

문제가 있나요? 알려주세요.

Azure SignalR Service에 사용자를 인증하는 함수 만들기

브라우저에서 채팅 앱을 처음 열 때 Azure SignalR Service에 연결하려면 유효한 연결 자격 증명이 필요합니다. 이 연결 정보를 반환하려면 함수 앱에서 negotiate라는 HTTP 트리거 함수를 만듭니다.

참고 항목

SignalR 클라이언트에는 /negotiate로 끝나는 엔드포인트가 필요하므로 이 함수의 이름은 negotiate로 지정되어야 합니다.

  1. 루트 프로젝트 폴더에서 다음 명령을 사용하여 기본 제공 템플릿에서 negotiate 함수를 만듭니다.

    func new --template "HTTP trigger" --name negotiate
    
  2. src/functions/negotiate.js 열고 다음과 같이 콘텐츠를 업데이트합니다.

    const { app, input } = require('@azure/functions');
    
    const inputSignalR = input.generic({
        type: 'signalRConnectionInfo',
        name: 'connectionInfo',
        hubName: 'default',
        connectionStringSetting: 'AzureSignalRConnectionString',
    });
    
    app.post('negotiate', {
        authLevel: 'anonymous',
        handler: (request, context) => {
            return { body: JSON.stringify(context.extraInputs.get(inputSignalR)) }
        },
        route: 'negotiate',
        extraInputs: [inputSignalR],
    });
    

    이 함수에는 SignalR 클라이언트로부터 요청을 수신하기 위한 HTTP 트리거 바인딩이 포함되어 있습니다. 이 함수에는 클라이언트가 default라는 Azure SignalR Service 허브에 연결하기 위한 유효한 자격 증명을 생성하는 SignalR 입력 바인딩도 포함되어 있습니다.

    이 함수는 입력 바인딩에서 SignalR 연결 정보를 가져와 HTTP 응답 본문의 클라이언트에 반환합니다.

    로컬 개발을 위한 signalRConnectionInfo 바인딩에는 userId 속성이 없습니다. 나중에 함수 앱을 Azure에 배포할 때 SignalR 연결의 사용자 이름을 설정하기 위해 추가합니다.

문제가 있나요? 알려주세요.

채팅 메시지를 보내는 함수 만들기

웹앱에는 채팅 메시지를 보내는 HTTP API가 필요합니다. Azure SignalR Service를 사용하는 연결된 모든 클라이언트에 메시지를 보내는 HTTP 트리거 함수를 만듭니다.

  1. 루트 프로젝트 폴더에서 다음 명령을 사용하여 템플릿에서 sendMessage라는 HTTP 트리거 함수를 만듭니다.

    func new --name sendMessage --template "Http trigger"
    
  2. src/functions/sendMessage.js 파일을 열고 다음과 같이 콘텐츠를 업데이트합니다.

    const { app, output } = require('@azure/functions');
    
    const signalR = output.generic({
        type: 'signalR',
        name: 'signalR',
        hubName: 'default',
        connectionStringSetting: 'AzureSignalRConnectionString',
    });
    
    app.http('messages', {
        methods: ['POST'],
        authLevel: 'anonymous',
        extraOutputs: [signalR],
        handler: async (request, context) => {
            const message = await request.json();
            message.sender = request.headers && request.headers.get('x-ms-client-principal-name') || '';
    
            let recipientUserId = '';
            if (message.recipient) {
                recipientUserId = message.recipient;
                message.isPrivate = true;
            }
            context.extraOutputs.set(signalR,
                {
                    'userId': recipientUserId,
                    'target': 'newMessage',
                    'arguments': [message]
                });
        }
    });
    

    함수에는 HTTP 트리거 및 SignalR 출력 바인딩이 포함됩니다. HTTP 요청에서 본문을 가져와서 Azure SignalR Service에 연결된 클라이언트로 보냅니다. 각 클라이언트에서 newMessage라는 함수를 호출합니다.

    이 함수는 보낸 사람의 ID를 읽을 수 있으며 메시지 본문의 recipient 값을 허용하여 단일 사용자에게 비공개로 메시지를 보낼 수 있습니다. 자습서의 뒷부분에서 이러한 기능을 사용합니다.

  3. 파일을 저장합니다.

문제가 있나요? 알려주세요.

채팅 클라이언트의 웹 사용자 인터페이스 호스팅

채팅 애플리케이션의 UI는 ASP.NET Core SignalR JavaScript 클라이언트를 사용하여 Vue JavaScript 프레임워크로 만든 간단한 SPA(단일 페이지 애플리케이션)입니다. 단순화를 위해 함수 앱은 웹 페이지를 호스팅합니다. 프로덕션 환경에서는 Static Web Apps를 사용하여 웹 페이지를 호스팅할 수 있습니다.

  1. 함수 프로젝트의 루트 디렉터리에 index.html 파일을 만듭니다.

  2. index.html의 콘텐츠를 복사하여 파일에 붙여넣습니다. 파일을 저장합니다.

  3. 루트 프로젝트 폴더에서 다음 명령을 사용하여 템플릿에서 index라는 HTTP 트리거 함수를 만듭니다.

    func new --name index --template "Http trigger"
    
  4. src/functions/index.js 콘텐츠를 다음 코드로 수정합니다.

    const { app } = require('@azure/functions');
    const { readFile } = require('fs/promises');
    
    app.http('index', {
        methods: ['GET'],
        authLevel: 'anonymous',
        handler: async (context) => {
            const content = await readFile('index.html', 'utf8', (err, data) => {
                if (err) {
                    context.err(err)
                    return
                }
            });
    
            return {
                status: 200,
                headers: {
                    'Content-Type': 'text/html'
                },
                body: content,
            };
        }
    });
    

    이 함수는 정적 웹 페이지를 읽고 이를 사용자에게 반환합니다.

  5. 앱을 로컬에서 테스트합니다. 다음 명령을 사용하여 함수 앱을 시작합니다.

    func start
    
  6. 웹 브라우저에서 http://localhost:7071/api/index를 엽니다. 채팅 웹 페이지가 나타납니다.

    로컬 채팅 클라이언트에 대한 웹 사용자 인터페이스의 스크린샷

  7. 채팅 상자에 메시지를 입력합니다.

    Enter 키를 선택하면 웹 페이지에 메시지가 나타납니다. SignalR 클라이언트의 사용자 이름이 설정되지 않았기 때문에 모든 메시지를 익명으로 보내고 있습니다.

문제가 있나요? 알려주세요.

Azure에 배포 및 인증을 사용하도록 설정

함수 앱과 채팅 앱을 로컬로 실행했습니다. 이제 이를 Azure에 배포하고 인증 및 프라이빗 메시징을 사용하도록 설정합니다.

인증을 위한 함수 앱 구성

지금까지 채팅 앱은 익명으로 작동합니다. Azure에서는 App Service 인증을 사용하여 사용자를 인증합니다. 인증된 사용자의 사용자 ID 또는 사용자 이름은 SignalRConnectionInfo 바인딩에 전달되어 사용자로 인증된 연결 정보를 생성합니다.

  1. src/functions/negotiate.js 파일을 엽니다.

  2. {headers.x-ms-client-principal-name} 값을 사용하여 userId 속성을 inputSignalR 바인딩에 삽입합니다. 이 값은 SignalR 클라이언트의 사용자 이름을 인증된 사용자의 이름으로 설정하는 바인딩 식입니다. 이제 바인딩은 다음 예와 같아야 합니다.

    const inputSignalR = input.generic({
        type: 'signalRConnectionInfo',
        name: 'connectionInfo',
        hubName: 'default',
        connectionStringSetting: 'AzureSignalRConnectionString',
        userId: '{headers.x-ms-client-principal-name}'
    });
    
  3. 파일을 저장합니다.

Azure에 함수 앱 배포

다음 명령을 사용하여 함수 앱을 Azure에 배포합니다.

func azure functionapp publish <your-function-app-name> --publish-local-settings

--publish-local-settings 옵션은 local.settings.json 파일에서 Azure로 로컬 설정을 게시하므로 Azure에서 다시 구성할 필요가 없습니다.

App Service 인증을 사용하도록 설정

Azure Functions는 Microsoft Entra ID, Facebook, Twitter, Microsoft 계정 및 Google을 통한 인증을 지원합니다. 이 자습서에서는 Microsoft를 ID 공급자로 사용합니다.

  1. Azure Portal에서 함수 앱의 리소스 페이지로 이동합니다.

  2. 설정>인증 선택합니다.

  3. ID 공급자 추가를 선택합니다.

    ID 공급자를 추가하기 위한 함수 앱 인증 페이지 및 단추의 스크린샷.

  4. ID 공급자 목록에서 Microsoft를 선택합니다. 그런 다음, 추가를 선택합니다.

    ID 공급자를 추가하기 위한 페이지의 스크린샷.

완료된 설정은 ID 공급자를 함수 앱과 연결하는 앱 등록을 만듭니다.

지원되는 ID 공급자에 대한 자세한 내용은 다음 문서를 참조하세요.

애플리케이션 사용해 보기

  1. https://<YOUR-FUNCTION-APP-NAME>.azurewebsites.net/api/index을(를) 여십시오.
  2. 로그인을 선택하여 선택한 인증 공급자를 통해 인증합니다.
  3. 기본 채팅 상자에 공용 메시지를 입력하여 보냅니다.
  4. 채팅 기록에서 사용자 이름을 선택하여 비공개 메시지를 보내세요. 선택한 수신자만 이 메시지를 받습니다.

인증된 온라인 클라이언트 채팅 앱의 스크린샷.

축하합니다! 실시간 서버리스 채팅 앱을 배포했습니다.

문제가 있나요? 알려주세요.

리소스 정리

이 자습서에서 만든 리소스를 정리하려면 Azure Portal을 사용하여 리소스 그룹을 삭제합니다.

주의

리소스 그룹을 삭제하면 포함된 모든 리소스가 삭제됩니다. 리소스 그룹에 이 자습서의 범위를 벗어나는 리소스가 포함되어 있으면 해당 리소스도 삭제됩니다.

문제가 있나요? 알려주세요.

다음 단계

이 자습서에서는 Azure SignalR Service에서 Azure Functions를 사용하는 방법을 알아보았습니다. Azure Functions에 대한 Azure SignalR Service 바인딩을 사용하여 실시간 서버리스 애플리케이션을 빌드하는 방법에 대해 자세히 알아보세요.

문제가 있나요? 알려주세요.