다음을 통해 공유


자습서: 백 엔드 API를 통해 App Service에서 Microsoft Graph로의 흐름 인증

프런트 엔드 앱의 사용자 자격 증명을 수락하도록 백 엔드 App Service를 만들고 구성한 다음 해당 자격 증명을 다운스트림 Azure 서비스에 교환하는 방법을 알아봅니다. 이렇게 하면 사용자가 프런트 엔드 App Service에 로그인하고, 자격 증명을 백 엔드 App Service에 전달한 다음, 동일한 ID로 Azure 서비스에 액세스할 수 있습니다.

이 튜토리얼에서는 다음을 배우게 됩니다:

  • 다운스트림 Azure 서비스에 범위가 지정된 토큰을 제공하도록 백 엔드 인증 앱 구성
  • JavaScript 코드를 사용하여 로그인한 사용자의 액세스 토큰을 다운스트림 서비스에 대한 새 토큰으로 교환합니다.
  • JavaScript 코드를 사용하여 다운스트림 서비스에 액세스합니다.

필수 조건

이 자습서를 시작하기 전에 보안 JavaScript 앱에서 사용자로 Microsoft Graph에 액세스하는 이전 자습서를 완료하지만 자습서가 끝날 때 리소스를 제거하지 마세요. 이 자습서에서는 두 개의 App Services와 해당 인증 앱이 있다고 가정합니다.

이전 자습서에서는 Azure CLOUD Shell을 Azure CLI의 셸로 사용했습니다. 이 자습서에서는 이 사용을 계속합니다.

건축학

이 자습서에서는 프런트 엔드 앱에서 제공하는 사용자 자격 증명을 백 엔드 앱에 전달한 다음 Azure 서비스에 전달하는 방법을 보여 줍니다. 이 자습서에서 다운스트림 서비스는 Microsoft Graph입니다. 사용자의 자격 증명은 Microsoft Graph에서 프로필을 가져오는 데 사용됩니다.

로그인한 사용자를 대신하여 Microsoft Graph에 연결하는 App Service의 아키텍처 이미지입니다.

사용자가 이 아키텍처에서 Microsoft Graph 정보를 가져오는 인증 흐름:

이전 자습서 에서는 다음을 다루었습니다.

  1. Active Directory를 ID 공급자로 사용하도록 구성된 프런트 엔드 App Service에 사용자를 로그인합니다.
  2. 프런트 엔드 App Service는 사용자의 토큰을 백 엔드 App Service에 전달합니다.
  3. 백 엔드 앱은 프런트 엔드가 API 요청을 만들 수 있도록 보호됩니다. 사용자의 액세스 토큰은 백엔드 API와 범위 user_impersonation에 대한 대상을 가집니다.
  4. 백엔드 애플리케이션 등록에는 범위가 있는 Microsoft Graph가 이미 포함되어 있습니다 User.Read. 기본적으로 모든 앱 등록에 추가됩니다.
  5. 이전 자습서의 끝에서 Graph가 연결되지 않았기 때문에 가짜 프로필이 프런트 엔드 앱으로 반환되었습니다.

이 자습서에서는 아키텍처를 확장합니다.

  1. 백 엔드 앱에 대한 사용자 동의 화면을 무시하도록 관리자 동의를 부여합니다.
  2. 프런트 엔드 앱에서 보낸 액세스 토큰을 Microsoft Graph에 필요한 권한이 있는 액세스 토큰으로 변환하도록 애플리케이션 코드를 변경합니다.
  3. Microsoft Graph와 같은 다운스트림 Azure 서비스의 범위를 사용하여 새 토큰에 대한 백 엔드 앱 교환 토큰 을 갖는 코드를 제공합니다.
  4. 백 엔드 앱이 새 토큰을 사용하여 현재 인증 사용자로 다운스트림 서비스에 액세스하도록 하는 코드를 제공합니다.
  5. 를 사용하여 백 엔드 앱을 az webapp up합니다.
  6. 이 자습서의 끝부분에는 그래프가 연결되었기 때문에 실제 프로필이 프런트 엔드 앱으로 반환됩니다.

이 자습서는 다음을 수행하지 않습니다.

  • 이전 자습서에서 프런트 엔드 앱을 변경합니다.
  • 기본적으로 모든 인증 앱에 User.Read이 추가되므로, 백엔드 인증 앱의 범위 권한을 변경합니다.

이전 자습서에서는 사용자가 프런트 엔드 앱에 로그인했을 때 사용자 동의를 요청하는 팝업이 표시됩니다.

이 자습서에서는 Microsoft Graph에서 사용자 프로필을 읽기 위해, 백엔드 앱이 로그인한 사용자의 액세스 토큰을 Microsoft Graph에 필요한 권한이 포함된 새 액세스 토큰으로 바꾸어야 합니다. 사용자가 백 엔드 앱에 직접 연결되지 않으므로 동의 화면에 대화형으로 액세스할 수 없습니다. 관리자 동의를 부여하려면 Microsoft Entra ID에서 백 엔드 앱의 앱 등록을 구성하여 이 작업을 수행해야 합니다. 이는 일반적으로 Active Directory 관리자가 수행하는 설정 변경입니다.

  1. Azure Portal을 열고 백 엔드 App Service에 대한 연구를 검색합니다.

  2. 설정 -> 인증 섹션을 찾습니다.

  3. ID 공급자를 선택하여 인증 앱으로 이동합니다.

  4. 인증 앱에서 관리 -> API 권한을 선택합니다.

  5. 기본 디렉터리에 대한 관리자 동의 부여를 선택합니다.

    관리자 동의 단추가 강조 표시된 Azure Portal 인증 앱의 스크린샷

  6. 팝업 창에서 예를 선택하여 동의를 확인합니다.

  7. 상태 열이 기본 디렉터리 부여됨으로 표시되는지 확인합니다. 이 설정을 사용하면 백 엔드 앱이 더 이상 로그인한 사용자에게 동의 화면을 표시할 필요가 없으며 액세스 토큰을 직접 요청할 수 있습니다. 로그인된 사용자는 앱 등록 시 생성되는 기본 범위인 User.Read 범위 설정에 액세스할 수 있습니다.

    상태 열에 관리자 동의가 부여된 Azure Portal 인증 앱의 스크린샷

2. npm 패키지 설치

이전 자습서에서는 Azure Portal에서 ID 공급자를 구성하여 유일한 인증을 제공했기 때문에 백 엔드 앱에 인증을 위한 npm 패키지가 필요하지 않았습니다. 이 자습서에서는 백 엔드 API에 대한 로그인한 사용자의 액세스 토큰을 해당 범위에서 Microsoft Graph와 액세스 토큰으로 교환해야 합니다. 이 교환은 더 이상 App Service 인증을 사용하지 않지만 Microsoft Entra ID 및 MSAL.js 직접 사용하기 때문에 두 개의 라이브러리로 완료됩니다.

  1. Azure Cloud Shell을 열고 샘플 디렉터리의 백 엔드 앱으로 변경합니다.

    cd js-e2e-web-app-easy-auth-app-to-app/backend
    
  2. Azure MSAL npm 패키지를 설치합니다.

    npm install @azure/msal-node
    
  3. Microsoft Graph npm 패키지를 설치합니다.

    npm install @microsoft/microsoft-graph-client
    

3. Microsoft Graph 토큰에 대한 현재 토큰을 교환하는 코드 추가

이 단계를 완료하기 위한 소스 코드가 제공됩니다. 다음 단계를 사용하여 포함합니다.

  1. ./src/server.js 파일을 엽니다.

  2. 파일 맨 위에 있는 다음 종속성의 주석을 해제합니다.

    import { getGraphProfile } from './with-graph/graph';
    
  3. 동일한 파일에서 graphProfile 변수의 주석을 제거하십시오.

    let graphProfile={};
    
  4. 동일한 파일에서 Microsoft Graph에서 프로필을 가져오려면 getGraphProfile 경로의 다음 get-profile 줄의 주석 처리를 제거하십시오.

    // where did the profile come from
    profileFromGraph=true;
    
    // get the profile from Microsoft Graph
    graphProfile = await getGraphProfile(accessToken);
    
    // log the profile for debugging
    console.log(`profile: ${JSON.stringify(graphProfile)}`);
    
  5. 변경 내용을 저장합니다. Ctrl s + .

  6. 백 엔드 앱을 다시 배포합니다.

    az webapp up --resource-group myAuthResourceGroup --name <back-end-app-name> 
    
    

4. 백 엔드 코드를 검사하여 Microsoft Graph 토큰에 대한 백 엔드 API 토큰 교환

Microsoft Graph 토큰에 대한 백 엔드 API 대상 토큰을 변경하려면 백 엔드 앱이 테넌트 ID를 찾아 MSAL.js 구성 개체의 일부로 사용해야 합니다. Microsoft를 ID 공급자로 구성한 백 엔드 앱은 테넌트 ID 및 기타 여러 필수 값이 App Service 앱 설정에 이미 있습니다.

샘플 앱에서 다음 코드가 이미 제공됩니다. 이 기능이 있는 이유와 작동 방식을 이해하여 이 동일한 기능이 필요한 빌드하는 다른 앱에 이 작업을 적용할 수 있도록 해야 합니다.

테넌트 ID를 가져오는 코드 검사

  1. ./backend/src/with-graph/auth.js 파일을 엽니다.

  2. getTenantId() 함수를 검토합니다.

    export function getTenantId() {
    
        const openIdIssuer = process.env.WEBSITE_AUTH_OPENID_ISSUER;
        const backendAppTenantId = openIdIssuer.replace(/https:\/\/sts\.windows\.net\/(.{1,36})\/v2\.0/gm, '$1');
    
        return backendAppTenantId;
    }
    
  3. 이 함수는 환경 변수에서 현재 테넌트 ID를 WEBSITE_AUTH_OPENID_ISSUER 가져옵니다. ID는 정규 표현식을 사용하여 변수에서 추출됩니다.

MSAL.js 사용하여 코드를 검사하여 그래프 토큰 가져오기

  1. ./backend/src/with-graph/auth.js 파일에서 여전히 getGraphToken() 함수를 검토하십시오.

  2. MSAL.js 구성 개체를 빌드하고 MSAL 구성을 사용하여 clientCredentialAuthority를 만듭니다. 대리 요청을 구성합니다. 그런 다음 acquireTokenOnBehalfOf를 사용하여 Graph 액세스 토큰에 대한 백 엔드 API 액세스 토큰을 교환합니다.

    // ./backend/src/auth.js
    // Exchange current bearerToken for Graph API token
    // Env vars were set by App Service
    export async function getGraphToken(backEndAccessToken) {
    
        const config = {
            // MSAL configuration
            auth: {
                // the backend's authentication CLIENT ID 
                clientId: process.env.WEBSITE_AUTH_CLIENT_ID,
                // the backend's authentication CLIENT SECRET 
                clientSecret: process.env.MICROSOFT_PROVIDER_AUTHENTICATION_SECRET,
                // OAuth 2.0 authorization endpoint (v2)
                // should be: https://login.microsoftonline.com/BACKEND-TENANT-ID
                authority: `https://login.microsoftonline.com/${getTenantId()}`
            },
            // used for debugging
            system: {
                loggerOptions: {
                    loggerCallback(loglevel, message, containsPii) {
                        console.log(message);
                    },
                    piiLoggingEnabled: true,
                    logLevel: MSAL.LogLevel.Verbose,
                }
            }
        };
    
        const clientCredentialAuthority = new MSAL.ConfidentialClientApplication(config);
    
        const oboRequest = {
            oboAssertion: backEndAccessToken,
            // this scope must already exist on the backend authentication app registration 
            // and visible in resources.azure.com backend app auth config
            scopes: ["https://graph.microsoft.com/.default"]
        }
    
        // This example has App service validate token in runtime
        // from headers that can't be set externally
    
        // If you aren't using App service's authentication, 
        // you must validate your access token yourself
        // before calling this code
        try {
            const { accessToken } = await clientCredentialAuthority.acquireTokenOnBehalfOf(oboRequest);
            return accessToken;
        } catch (error) {
            console.log(`getGraphToken:error.type = ${error.type}  ${error.message}`);
        }
    }
    

5. 백 엔드 코드를 검사하여 새 토큰으로 Microsoft Graph에 액세스

프런트 엔드 애플리케이션에 로그인한 사용자로 Microsoft Graph에 액세스하기 위해 변경 내용은 다음과 같습니다.

  • 필요한 범위를 User.Read사용하여 다운스트림 서비스인 Microsoft Graph에 대한 API 권한으로 Active Directory 앱 등록 구성
  • 백 엔드 앱에 대한 사용자 동의 화면을 무시하도록 관리자 동의를 부여합니다.
  • 프런트 엔드 앱에서 보낸 액세스 토큰을 다운스트림 서비스 Microsoft Graph에 필요한 권한이 있는 액세스 토큰으로 변환하도록 애플리케이션 코드를 변경합니다.

이제 코드에 Microsoft Graph에 대한 올바른 토큰이 있으므로 이 토큰을 사용하여 Microsoft Graph에 클라이언트를 만든 다음 사용자의 프로필을 가져옵니다.

  1. ./backend/src/graph.js을 여세요.

  2. 함수에서 getGraphProfile() 토큰을 가져오고 토큰에서 인증된 클라이언트를 가져오고 프로필을 가져옵니다.

    // 
    import graph from "@microsoft/microsoft-graph-client";
    import { getGraphToken } from "./auth.js";
    
    // Create client from token with Graph API scope
    export function getAuthenticatedClient(accessToken) {
        const client = graph.Client.init({
            authProvider: (done) => {
                done(null, accessToken);
            }
        });
    
        return client;
    }
    export async function getGraphProfile(accessToken) {
        // exchange current backend token for token with 
        // graph api scope
        const graphToken = await getGraphToken(accessToken);
    
        // use graph token to get Graph client
        const graphClient = getAuthenticatedClient(graphToken);
    
        // get profile of user
        const profile = await graphClient
            .api('/me')
            .get();
    
        return profile;
    }
    

6. 변경 내용 테스트

  1. 브라우저에서 프런트 엔드 웹 사이트를 사용합니다. 토큰이 만료된 경우 토큰을 새로 고쳐야 할 수 있습니다.

  2. Get user's profile를 선택합니다. 이는 전달자 토큰의 인증을 백 엔드로 전달합니다.

  3. 백 엔드는 계정에 대한 실제 Microsoft Graph 프로필로 응답합니다.

    백 엔드 앱에서 실제 프로필을 성공적으로 얻은 후 프런트 엔드 애플리케이션을 보여 주는 웹 브라우저의 스크린샷

7. 정리

이전 단계에서는 리소스 그룹에서 Azure 리소스를 만들었습니다.

  1. Cloud Shell에서 다음 명령을 실행하여 리소스 그룹을 삭제합니다. 이 명령을 실행하는 데 1분 정도 걸릴 수 있습니다.

    az group delete --name myAuthResourceGroup
    
  2. 이전에 백 엔드 및 프런트 엔드 앱에 대한 섹션에서 찾아서 기록한 인증 앱의 Enable authentication and authorization를 사용합니다.

  3. 프런트 엔드 및 백 엔드 앱 모두에 대한 앱 등록을 삭제합니다.

    # delete app - do this for both frontend and backend client ids
    az ad app delete <client-id>
    

자주 묻는 질문

오류가 80049217발생했습니다. 무엇을 의미하나요?

이 오류는 CompactToken parsing failed with error code: 80049217 백엔드 앱 서비스가 Microsoft Graph 토큰을 반환할 수 있도록 승인되지 않았다는 것을 의미합니다. 이 오류는 앱 등록에 User.Read 사용 권한이 없어서 발생합니다.

오류가 AADSTS65001발생했습니다. 무엇을 의미하나요?

이 오류는 AADSTS65001: The user or administrator has not consented to use the application with ID \<backend-authentication-id>. Send an interactive authorization request for this user and resource백 엔드 인증 앱이 관리자 동의를 위해 구성되지 않았음을 의미합니다. 오류가 백 엔드 앱의 로그에 표시되기 때문에 프런트 엔드 애플리케이션은 프런트 엔드 앱에서 프로필이 보이지 않는 이유를 사용자에게 알릴 수 없습니다.

다른 다운스트림 Azure 서비스에 사용자로 연결하려면 어떻게 해야 하나요?

이 자습서에서는 Microsoft Graph에 인증된 API 앱을 보여 줍니다. 그러나 사용자를 대신하여 모든 Azure 서비스에 액세스하기 위해 동일한 일반 단계를 적용할 수 있습니다.

  1. 프런트 엔드 애플리케이션은 변경되지 않습니다. 백 엔드의 인증 앱 등록 및 백 엔드 앱 소스 코드만 변경합니다.
  2. 사용자에게 백엔드 API에 대해 범위가 지정된 토큰을, 액세스하고자 하는 다운스트림 서비스에 대한 토큰으로 교환합니다.
  3. 다운스트림 서비스의 SDK에서 토큰을 사용하여 클라이언트를 만듭니다.
  4. 다운스트림 클라이언트를 사용하여 서비스 기능에 액세스합니다.

다음 단계