자습서: 백 엔드 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 정보를 가져올 수 있는 인증 흐름:
이전 자습서에서 다룬 내용:
- Active Directory를 ID 공급자로 사용하도록 구성된 프런트 엔드 App Service에 사용자를 로그인합니다.
- 프런트 엔드 App Service는 사용자의 토큰을 백 엔드 App Service에 전달합니다.
- 백 엔드 앱은 프런트 엔드가 API 요청을 만들 수 있도록 보호됩니다. 사용자의 액세스 토큰에는 백 엔드 API 및
user_impersonation
의 범위에 대한 대상 그룹이 있습니다. - 백 엔드 앱 등록에 범위가
User.Read
인 Microsoft Graph가 이미 있습니다. 기본적으로 모든 앱 등록에 추가됩니다. - 이전 자습서의 끝 부분에서 Graph가 연결되지 않았기 때문에 가짜 프로필이 프런트 엔드 앱에 반환되었습니다.
이 자습서에서는 아키텍처를 확장합니다.
- 백 엔드 앱에 대한 사용자 동의 화면을 무시하도록 관리자 동의를 승인합니다.
- 애플리케이션 코드를 변경하여 프런트 엔드 앱에서 보낸 액세스 토큰을 Microsoft Graph에 필요한 권한이 있는 액세스 토큰으로 변환합니다.
- Microsoft Graph와 같은 다운스트림 Azure 서비스의 범위를 사용하여 백 엔드 앱에서 새 토큰으로 토큰을 교환하도록 하는 코드를 제공합니다.
- 백 엔드 앱에서 새 토큰을 사용하여 현재 인증 사용자로 다운스트림 서비스에 액세스할 수 있는 코드를 제공합니다.
az webapp up
을 사용하여 백 엔드 앱을 재배포합니다.- 이 자습서의 끝 부분에는 그래프가 연결되어 있기 때문에 실제 프로필이 프런트 엔드 앱으로 반환됩니다.
이 자습서에서는 다음을 수행하지 않습니다.
- 이전 자습서의 프런트 엔드 앱을 변경하지 않습니다.
User.Read
는 기본적으로 모든 인증 앱에 추가되므로 백 엔드 인증 앱의 범위 권한을 변경하지 않습니다.
1. 백 엔드 앱에 대한 관리자 동의 구성
이전 자습서에서는 사용자가 프런트 엔드 앱에 로그인했을 때 사용자 동의를 요청하는 팝업이 표시되었습니다.
이 자습서에서는 Microsoft Graph에서 사용자 프로필을 읽기 위해 백 엔드 앱이 로그인한 사용자의 액세스 토큰을 새 액세스 토큰과 Microsoft Graph에 필요한 권한으로 교환해야 합니다. 사용자는 백 엔드 앱에 직접 연결되지 않으므로 동의 화면에 대화형으로 액세스할 수 없습니다. 관리자 동의를 승인하려면 Microsoft Entra ID에서 백 엔드 앱의 앱 등록을 구성하여 이 문제를 해결해야 합니다. 이는 일반적으로 Active Directory 관리자가 수행하는 설정 변경입니다.
Azure Portal을 열고 백 엔드 App Service에 대한 연구를 검색합니다.
설정 -> 인증 섹션을 찾습니다.
ID 공급자를 선택하여 인증 앱으로 이동합니다.
인증 앱에서 관리 -> API 권한을 선택합니다.
기본 디렉터리에 대한 관리자 동의 부여를 선택합니다.
팝업 창에서 예를 선택하여 동의를 확인합니다.
상태 열에 기본 디렉터리에 대해 부여됨이 표시되는지 확인합니다. 이 설정을 사용하면 백 엔드 앱이 더 이상 로그인한 사용자에게 동의 화면을 표시할 필요 없이 액세스 토큰을 직접 요청할 수 있습니다. 로그인한 사용자는
User.Read
범위 설정에 액세스할 수 있습니다. 이 범위는 앱 등록이 생성되는 기본 범위이기 때문입니다.
2. npm 패키지 설치
이전 자습서에서는 Azure Portal ID 공급자를 구성하여 유일한 인증을 제공했기 때문에 백 엔드 앱에 인증을 위한 npm 패키지가 필요하지 않았습니다. 이 자습서에서는 로그인한 사용자의 백 엔드 API에 대한 액세스 토큰을 해당 범위의 Microsoft Graph와 액세스 토큰으로 교환해야 합니다. 이 교환은 더 이상 App Service 인증을 사용하지 않지만 Microsoft Entra ID 및 MSAL.js를 직접 사용하기 때문에 두 개의 라이브러리로 완료됩니다.
- @azure/MSAL-node - 교환 토큰
- @microsoft/microsoft-graph-client - Microsoft Graph에 연결
Azure Cloud Shell을 열고 샘플 디렉터리의 백 엔드 앱으로 변경:
cd js-e2e-web-app-easy-auth-app-to-app/backend
Azure MSAL npm 패키지 설치:
npm install @azure/msal-node
Microsoft Graph npm 패키지 설치:
npm install @microsoft/microsoft-graph-client
3. 현재 토큰을 Microsoft Graph 토큰으로 교환하는 코드 추가
이 단계를 완료하기 위한 소스 코드가 제공됩니다. 다음 단계를 사용하여 이 코드를 포함합니다.
./src/server.js
파일을 엽니다.파일 맨 위에서 다음 종속성의 주석 처리 제거:
import { getGraphProfile } from './with-graph/graph';
동일한 파일에서
graphProfile
변수의 주석 처리 제거:let graphProfile={};
동일한 파일에서
get-profile
경로의 다음getGraphProfile
줄의 주석 처리를 제거하여 Microsoft Graph에서 프로필 가져오기:// 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)}`);
변경 내용 저장: Ctrl + s.
백 엔드 앱 재배포:
az webapp up --resource-group myAuthResourceGroup --name <back-end-app-name>
4. 백 엔드 코드를 검사하여 백 엔드 API 토큰을 Microsoft Graph 토큰으로 교환
백 엔드 API 대상 그룹 토큰을 Microsoft Graph 토큰으로 변경하려면 백 엔드 앱이 테넌트 ID를 찾고 이를 사용하여 MSAL.js 구성 개체의 일부로 사용해야 합니다. Microsoft를 ID 공급자로 구성한 백 엔드 앱은 테넌트 ID 및 기타 몇몇 필수 값이 이미 App Service 앱 설정에 있습니다.
샘플 앱에는 이미 다음 코드가 제공되어 있습니다. 이 코드가 있는 이유와 작동 방식을 이해하여 빌드하는 다른 앱에 이 동일한 기능이 필요한 경우 이 작업을 적용할 수 있도록 해야 합니다.
테넌트 ID를 가져오기 위한 코드 검사
./backend/src/with-graph/auth.js
파일을 엽니다.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; }
이 함수는
WEBSITE_AUTH_OPENID_ISSUER
환경 변수에서 현재 테넌트 ID를 가져옵니다. ID는 정규식을 사용하여 변수에서 구문 분석됩니다.
코드를 검사하여 MSAL.js를 사용하여 Graph 토큰 가져오기
./backend/src/with-graph/auth.js
파일에서getGraphToken()
함수를 검토합니다.MSAL.js 구성 개체를 빌드하고 MSAL 구성을 사용하여 clientCredentialAuthority를 만듭니다. on-behalf-off 요청을 구성합니다. 그런 다음 acquireTokenOnBehalfOf를 사용하여 백 엔드 API 액세스 토큰을 Graph 액세스 토큰으로 교환합니다.
// ./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에 클라이언트를 만든 다음, 사용자의 프로필을 가져옵니다.
./backend/src/graph.js
열기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. 변경 내용 테스트
브라우저에서 프런트 엔드 웹 사이트를 사용합니다. URL은
https://<front-end-app-name>.azurewebsites.net/
형식입니다. 토큰이 만료된 경우 토큰을 새로 고쳐야 할 수 있습니다.Get user's profile
를 선택합니다. 이는 전달자 토큰의 인증을 백 엔드로 전달합니다.백 엔드는 계정의 실제 Microsoft Graph 프로필로 응답합니다.
7. 정리
이전 단계에서는 리소스 그룹에서 Azure 리소스를 만들었습니다.
Cloud Shell에서 다음 명령을 실행하여 리소스 그룹을 삭제합니다. 이 명령을 실행하는 데 1분 정도 걸릴 수 있습니다.
az group delete --name myAuthResourceGroup
이전에 백 엔드 및 프런트 엔드 앱에 대한
Enable authentication and authorization
섹션에서 찾아서 기록한 인증 앱의 클라이언트 ID를 사용합니다.프런트 엔드 및 백 엔드 앱 모두에 대한 앱 등록을 삭제합니다.
# 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
)는 백 엔드 App Service가 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 서비스에 액세스할 수 있습니다.
- 프런트 엔드 애플리케이션은 변경되지 않습니다. 백 엔드의 인증 앱 등록 및 백 엔드 앱 소스 코드만 변경됩니다.
- 백 엔드 API로 범위가 지정된 사용자의 토큰을 액세스하려는 다운스트림 서비스에 대한 토큰으로 교환합니다.
- 다운스트림 서비스의 SDK에서 토큰을 사용하여 클라이언트를 만듭니다.
- 다운스트림 클라이언트를 사용하여 서비스 기능에 액세스합니다.