연습 - MSAL을 통해 사용자 로그인

완료됨

이 연습에서는 MSAL4J(Microsoft Authentication Library for Java)를 사용하여 샘플 Java 웹 애플리케이션에서 인증을 추가하고 사용자가 Microsoft Entra 계정으로 로그인할 수 있도록 합니다.

이 연습에서 사용할 샘플 애플리케이션은 사용자가 로그인할 수 있도록 하고 사용자 이름 및 기본 프로필 정보를 표시하는 Java 서블릿 애플리케이션입니다. 또한 Microsoft Graph API를 호출하여 일부 사용자 정보를 표시할 수도 있습니다.

Java 웹 애플리케이션 만들기

셸 또는 명령줄에서 다음 명령을 실행합니다.

  1. 애플리케이션에 대한 폴더를 만듭니다.

    mkdir ~/javawebapp
    
  2. GitHub 리포지토리의 샘플 애플리케이션을 새 폴더에 복제합니다.

    git clone https://github.com/Azure-Samples/ms-identity-java-servlet-webapp-authentication.git ~/javawebapp
    
  3. 이 연습의 샘플 애플리케이션이 있는 폴더로 변경합니다.

    cd ~/javawebapp/ms-identity-java-servlet-webapp-authentication/2-Authorization-I/call-graph
    

애플리케이션 구성

코드를 구성하려면 IntelliJ 또는 VS Code 같은 기본 설정 IDE에서 애플리케이션 프로젝트를 엽니다.

  1. ./src/main/resources/authentication.properties 파일을 엽니다.

  2. 문자열 {enter-your-tenant-id-here}를 찾습니다. 앱이 이 조직 디렉터리의 계정만 옵션을 사용하여 등록되었으므로 기존 값을 다음 이미지와 같이 디렉터리(테넌트) ID로 바꿉니다.

  3. 문자열 {enter-your-client-id-here}를 찾아 기존 값을 Azure Portal에서 복사한 등록된 애플리케이션의 애플리케이션(클라이언트) ID(clientId)로 바꿉니다.

    Screenshot highlighting the App ID of an app registered with Microsoft Entra ID on Azure portal.

  4. 문자열 {enter-your-client-secret-here}을 찾아 기존 값을 Azure Portal에서 앱을 만드는 동안 저장한 로 바꿉니다.

애플리케이션 실행

  1. Tomcat 서버가 실행 중이고 웹앱을 배포할 수 있는 권한이 있는지 확인합니다. 서버 호스트 주소가 http://localhost:8080인지 확인합니다.

  2. Maven을 사용하여 프로젝트를 컴파일하고 패키지합니다.

    cd ~/javawebapp/2-Authorization-I/call-graph
    mvn clean package
    
  3. ./target/msal4j-servlet-graph.war에서 결과 .war 파일을 찾습니다. Tomcat에 배포하려면 이 .war 파일을 Tomcat 설치 디렉터리에 있는 /webapps/ 디렉터리에 복사하고 Tomcat 서버를 시작합니다.

  4. 브라우저를 열고 http://localhost:8080/msal4j-servlet-graph/로 이동합니다. Microsoft Entra ID로 로그인하도록 리디렉션됩니다. 로그인에 성공하면 다음과 같은 페이지가 표시됩니다.

    Screenshot showing user name displayed on the page after successfully signing in to sample application.

  5. ID 토큰 세부 정보 단추를 선택하여 ID 토큰의 디코딩된 클레임을 확인합니다.

인증 코드 개요

프로젝트의 java/com/microsoft/azuresamples/msal4j/ 디렉터리 아래에 있는 샘플 애플리케이션에서 대부분의 인증 코드를 찾을 수 있습니다. 여기에는 로그인, 로그아웃 및 Microsoft Entra ID의 리디렉션 콜백 처리를 위해 애플리케이션에서 인증 엔드포인트를 제공하는 여러 서블릿이 포함되어 있습니다. 이러한 서블릿은 디렉터리 java/com/microsoft/azuresamples/msal4j/helpers/의 도우미 클래스를 사용하여 MSAL에서 제공하는 인증 메서드를 호출합니다. 보호된 경로에 대한 인증되지 않은 요청을 401 권한 없는 HTTP 오류 페이지로 리디렉션하는 서블릿 필터가 AuthenticationFilter.java에 정의되어 있습니다.

애플리케이션에 인증을 추가하려면 java/com/microsoft/azuresamples/msal4j/authservletsjava/com/microsoft/azuresamples/msal4j/authwebapp 디렉터리에 서블릿 클래스를, java/com/microsoft/azuresamples/msal4j/helpers/ 디렉터리에 도우미 클래스를, 프로젝트에 AuthenticationFilter.java 인증 서블릿 필터를 포함해야 합니다. MSAL 인증 코드에 대한 자세한 내용은 다음과 같습니다.

  1. MSAL4J는 Maven에서 사용할 수 있습니다. MSAL4J를 프로젝트의 pom.xml 파일에 종속성으로 추가해야 합니다.

    <dependency>
        <groupId>com.microsoft.azure</groupId>
        <artifactId>msal4j</artifactId>
        <version>1.9.1</version>
    </dependency>
    
  2. 로그인 프로세스의 첫 번째 단계는 Microsoft Entra 테넌트의 /authorize 엔드포인트에 요청을 보내는 것입니다. MSAL4J ConfidentialClientApplication 인스턴스는 권한 부여 요청 URL을 구성하는 데 활용됩니다. 앱은 사용자가 로그인하는 이 URL로 브라우저를 리디렉션합니다.

    final ConfidentialClientApplication client = getConfidentialClientInstance();
    AuthorizationRequestUrlParameters parameters = AuthorizationRequestUrlParameters
                                                        .builder(Config.REDIRECT_URI, Collections.singleton(Config.SCOPES))
                                                        .responseMode(ResponseMode.QUERY).prompt(Prompt.SELECT_ACCOUNT).state(state).nonce(nonce).build();
    
    final String authorizeUrl = client.getAuthorizationRequestUrl(parameters).toString();
    contextAdapter.redirectUser(authorizeUrl);
    
    • AuthorizationRequestUrlParameters: AuthorizationRequestUrl을 빌드하기 위해 설정해야 하는 매개 변수입니다.
    • REDIRECT_URI: 리디렉션 URI는 ID 공급자가 보안 토큰을 다시 보낼 URI입니다. Microsoft Entra ID는 사용자 자격 증명을 수집한 후 인증 코드와 함께 브라우저를 이 URI로 리디렉션합니다. Microsoft Entra 앱 등록의 리디렉션 URI와 일치해야 합니다.
    • SCOPES: 범위는 애플리케이션에서 요청한 권한입니다. 일반적으로 세 가지 범위 openid profile offline_access는 사용자 로그인에 대한 ID 토큰 응답을 받는 데 충분하며 이러한 범위는 기본적으로 MSAL에서 설정됩니다.
  3. 사용자에게 Microsoft Entra ID의 로그인 프롬프트가 표시됩니다. 로그인 시도가 성공하면 사용자의 브라우저가 엔드포인트에서 유효한 권한 부여 코드를 사용하여 앱의 리디렉션 엔드포인트로 리디렉션됩니다. 그런 다음 ConfidentialClientApplication 인스턴스는 이 인증 코드를 Microsoft Entra ID의 ID 토큰 및 액세스 토큰으로 교환합니다.

    // First, validate the state, then parse any error codes in response, then extract the authCode. Then:
    // build the auth code params:
    final AuthorizationCodeParameters authParams = AuthorizationCodeParameters
                                                        .builder(authCode, new URI(Config.REDIRECT_URI)).scopes(Collections.singleton(Config.SCOPES)).build();
    
    // Get a client instance and leverage it to acquire the token:
    final ConfidentialClientApplication client = AuthHelper.getConfidentialClientInstance();
    final IAuthenticationResult result = client.acquireToken(authParams).get();
    
    • AuthorizationCodeParameters: 권한 부여 코드를 ID 및/또는 액세스 토큰으로 교환하기 위해 설정해야 하는 매개 변수입니다.
    • authCode: 리디렉션 엔드포인트에서 받은 권한 부여 코드입니다.
    • REDIRECT_URI: 이전 단계에서 사용된 리디렉션 URI를 다시 전달해야 합니다.
    • SCOPES: 이전 단계에서 사용된 범위를 다시 전달해야 합니다.
  4. acquireToken이 성공하면 토큰 클레임이 추출됩니다. nonce 검사를 통과하면 결과가 context(IdentityContextData의 인스턴스)에 배치되고 세션에 저장됩니다. 그런 다음, 애플리케이션은 다음에 액세스해야 할 때마다 세션에서 인스턴스화할 수 있습니다(IdentityContextAdapterServlet 인스턴스를 통해).

    // parse IdToken claims from the IAuthenticationResult:
    // (the next step - validateNonce - requires parsed claims)
    context.setIdTokenClaims(result.idToken());
    
    // if nonce is invalid, stop immediately! this could be a token replay!
    // if validation fails, throws exception and cancels auth:
    validateNonce(context);
    
    // set user to authenticated:
    context.setAuthResult(result, client.tokenCache().serialize());