다음을 통해 공유


자습서: Node.js 웹 애플리케이션에 로그인 및 로그아웃 추가

이 자습서는 Node.js 웹앱을 빌드하고 Microsoft Entra 관리 센터를 사용하여 인증을 준비하는 방법을 설명하는 시리즈의 마지막 부분입니다. 이 시리즈의 2부에서는 Node.js 웹앱을 만들고 필요한 모든 파일을 구성했습니다. 이 자습서에서는 Node.js 웹앱에 로그인, 등록 및 로그아웃을 추가합니다. Node.js 웹앱에 인증 추가를 간소화하려면 Node용 MSAL(Microsoft 인증 라이브러리)을 사용합니다. 로그인 흐름에서는 사용자를 안전하게 로그인시키는 OIDC(OpenID Connect) 인증 프로토콜을 사용합니다.

이 자습서에서는 다음을 수행합니다.

  • 로그인 및 로그아웃 논리 추가
  • ID 토큰 클레임 보기
  • 앱을 실행하고 로그인 및 로그아웃 환경을 테스트합니다.

필수 조건

MSAL 구성 개체 만들기

코드 편집기에서 authConfig.js 파일을 연 다음, 다음 코드를 추가합니다.

require('dotenv').config();

const TENANT_SUBDOMAIN = process.env.TENANT_SUBDOMAIN || 'Enter_the_Tenant_Subdomain_Here';
const REDIRECT_URI = process.env.REDIRECT_URI || 'http://localhost:3000/auth/redirect';
const POST_LOGOUT_REDIRECT_URI = process.env.POST_LOGOUT_REDIRECT_URI || 'http://localhost:3000';

/**
 * Configuration object to be passed to MSAL instance on creation.
 * For a full list of MSAL Node configuration parameters, visit:
 * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/configuration.md
 */
const msalConfig = {
    auth: {
        clientId: process.env.CLIENT_ID || 'Enter_the_Application_Id_Here', // 'Application (client) ID' of app registration in Azure portal - this value is a GUID
        authority: process.env.AUTHORITY || `https://${TENANT_SUBDOMAIN}.ciamlogin.com/`, // replace "Enter_the_Tenant_Subdomain_Here" with your tenant name
        clientSecret: process.env.CLIENT_SECRET || 'Enter_the_Client_Secret_Here', // Client secret generated from the app registration in Azure portal
    },
    system: {
        loggerOptions: {
            loggerCallback(loglevel, message, containsPii) {
                console.log(message);
            },
            piiLoggingEnabled: false,
            logLevel: 'Info',
        },
    },
};

module.exports = {
    msalConfig,
    REDIRECT_URI,
    POST_LOGOUT_REDIRECT_URI,
    TENANT_SUBDOMAIN
};

msalConfig 개체에는 인증 흐름의 동작을 사용자 지정하는 데 사용하는 구성 옵션 집합이 포함되어 있습니다.

authConfig.js 파일에서 다음을 대체합니다.

  • Enter_the_Application_Id_Here를 이전에 등록한 앱의 애플리케이션(클라이언트) ID로 바꿉니다.

  • Enter_the_Tenant_Subdomain_Here를 디렉터리(테넌트) 하위 도메인으로 바꿉니다. 예를 들어, 테넌트 기본 도메인이 contoso.onmicrosoft.com인 경우 contoso를 사용합니다. 테넌트 이름이 없는 경우 테넌트 세부 정보를 읽는 방법을 알아봅니다.

  • Enter_the_Client_Secret_Here를 이전에 복사한 앱 비밀 값으로 바꿉니다.

.env 파일을 사용하여 구성 정보를 저장하는 경우:

  1. 코드 편집기에서 .env 파일을 열고 다음 코드를 추가합니다.

        CLIENT_ID=Enter_the_Application_Id_Here
        TENANT_SUBDOMAIN=Enter_the_Tenant_Subdomain_Here
        CLIENT_SECRET=Enter_the_Client_Secret_Here
        REDIRECT_URI=http://localhost:3000/auth/redirect
        POST_LOGOUT_REDIRECT_URI=http://localhost:3000
    
  2. 앞에서 설명한 대로 Enter_the_Application_Id_Here, Enter_the_Tenant_Subdomain_HereEnter_the_Client_Secret_Here 자리 표시자를 바꿉니다.

authConfig.js 파일에서 msalConfig, REDIRECT_URI, TENANT_SUBDOMAINPOST_LOGOUT_REDIRECT_URI 변수를 내보내면 파일이 필요할 때마다 해당 변수에 액세스할 수 있습니다.

사용자 지정 URL 도메인 사용(선택 사항)

사용자 지정 도메인을 사용하여 인증 URL을 완전히 브랜딩합니다. 사용자 관점에서 볼 때, 사용자는 인증 과정 동안 ciamlogin.com 도메인 이름으로 리디렉션되는 것이 아니라 도메인에 남아 있습니다.

사용자 지정 도메인을 사용하려면 다음 단계를 따릅니다.

  1. 외부 테넌트에 대한 사용자 지정 URL 도메인을 사용하도록 설정하려면 외부 테넌트의 앱에 대한 사용자 지정 URL 도메인 사용의 단계를 사용합니다.

  2. authConfig.js 파일에서 auth 개체를 찾은 후 다음을 수행합니다.

    1. authority 속성의 값을 https://Enter_the_Custom_Domain_Here/Enter_the_Tenant_ID_Here로 업데이트합니다. Enter_the_Custom_Domain_Here를 사용자 지정 URL 도메인으로, Enter_the_Tenant_ID_Here를 테넌트 ID로 바꿉니다. 테넌트 ID가 없는 경우 테넌트 세부 정보를 읽는 방법을 알아봅니다.
    2. [Enter_the_Custom_Domain_Here] 값을 갖는 knownAuthorities 속성을 추가합니다.

authConfig.js 파일을 변경한 후 사용자 지정 URL 도메인이 login.contoso.com이고 테넌트 ID가 aaaabbbb-0000-cccc-1111-dddd2222eeee인 경우 파일은 다음 코드 조각과 유사해야 합니다.

//...
const msalConfig = {
    auth: {
        authority: process.env.AUTHORITY || 'https://login.contoso.com/aaaabbbb-0000-cccc-1111-dddd2222eeee', 
        knownAuthorities: ["login.contoso.com"],
        //Other properties
    },
    //...
};

Express 경로 추가

기본 경로는 로그인, 로그아웃 및 ID 토큰 클레임 보기와 같은 작업을 실행할 수 있는 엔드포인트를 제공합니다.

앱 진입점

코드 편집기에서 routes/index.js 파일을 연 다음, 다음 코드를 추가합니다.

const express = require('express');
const router = express.Router();

router.get('/', function (req, res, next) {
    res.render('index', {
        title: 'MSAL Node & Express Web App',
        isAuthenticated: req.session.isAuthenticated,
        username: req.session.account?.username !== '' ? req.session.account?.username : req.session.account?.name,
    });
});    
module.exports = router;

/ 경로는 애플리케이션의 진입점입니다. 이는 앞서 앱 UI 구성 요소 빌드에서 만든 views/index.hbs 뷰를 렌더링합니다. isAuthenticated는 뷰에 표시되는 내용을 결정하는 부울 변수입니다.

로그인 및 로그아웃

  1. 코드 편집기에서 routes/auth.js 파일을 연 다음 auth.js 코드를 추가합니다.

  2. 코드 편집기에서 controller/authController.js 파일을 연 다음 authController.js 코드를 추가합니다.

  3. 코드 편집기에서 auth/AuthProvider.js 파일을 연 다음 AuthProvider.js 코드를 추가합니다.

    /signin, /signout/redirect 경로는 routes/auth.js 파일에 정의되어 있지만 해당 논리는 auth/AuthProvider.js 클래스에서 구현합니다.

  • login 메서드는 /signin 경로를 처리합니다.

    • 인증 코드 흐름의 첫 번째 구간을 트리거하여 로그인 흐름을 시작합니다.

    • 이전에 만든 MSAL 구성 개체 msalConfig를 사용하여 기밀 클라이언트 애플리케이션 인스턴스를 초기화합니다.

          const msalInstance = this.getMsalInstance(this.config.msalConfig);
      

      getMsalInstance 메서드는 다음과 같이 정의됩니다.

          getMsalInstance(msalConfig) {
              return new msal.ConfidentialClientApplication(msalConfig);
          }
      
    • 인증 코드 흐름의 첫 번째 레그는 인증 코드 요청 URL을 생성한 다음, 해당 URL로 리디렉션하여 인증 코드를 가져옵니다. 이 첫 번째 레그는 redirectToAuthCodeUrl 메서드에서 구현됩니다. MSAL getAuthCodeUrl 메서드를 사용하여 인증 코드 URL을 생성하는 방법을 확인하세요.

      //...
      const authCodeUrlResponse = await msalInstance.getAuthCodeUrl(req.session.authCodeUrlRequest);
      //...
      

      그런 다음 인증 코드 URL 자체로 리디렉션합니다.

      //...
      res.redirect(authCodeUrlResponse);
      //...
      
  • handleRedirect 메서드는 /redirect 경로를 처리합니다.

    • 이 URL은 웹앱 등록의 앞부분에서 Microsoft Entra 관리 센터에서 웹앱에 대한 리디렉션 URI로 설정했습니다.

    • 이 엔드포인트는 인증 코드 흐름에서 사용하는 두 번째 레그를 구현합니다. 인증 코드를 사용하여 MSAL의 acquireTokenByCode 메서드를 사용하여 ID 토큰을 요청합니다.

      //...
      const tokenResponse = await msalInstance.acquireTokenByCode(authCodeRequest, req.body);
      //...
      
    • 응답을 받은 후 Express 세션을 만들고 원하는 정보를 저장할 수 있습니다. isAuthenticated를 포함하고 true로 설정해야 합니다.

      //...        
      req.session.idToken = tokenResponse.idToken;
      req.session.account = tokenResponse.account;
      req.session.isAuthenticated = true;
      //...
      
  • logout 메서드는 /signout 경로를 처리합니다.

    async logout(req, res, next) {
        /**
         * Construct a logout URI and redirect the user to end the
            * session with Azure AD. For more information, visit:
            * https://docs.microsoft.com/azure/active-directory/develop/v2-protocols-oidc#send-a-sign-out-request
            */
        const logoutUri = `${this.config.msalConfig.auth.authority}${TENANT_SUBDOMAIN}.onmicrosoft.com/oauth2/v2.0/logout?post_logout_redirect_uri=${this.config.postLogoutRedirectUri}`;
    
        req.session.destroy(() => {
            res.redirect(logoutUri);
        });
    }
    
    • 로그아웃 요청이 시작됩니다.

    • 사용자를 애플리케이션에서 로그아웃하려는 경우 사용자 세션을 종료하는 것만으로는 충분하지 않습니다. 사용자를 logoutUri로 리디렉션해야 합니다. 그렇지 않으면 사용자가 자격 증명을 다시 입력하지 않고 애플리케이션에 다시 인증할 수 있습니다. 테넌트 이름이 contoso인 경우 logoutUrihttps://contoso.ciamlogin.com/contoso.onmicrosoft.com/oauth2/v2.0/logout?post_logout_redirect_uri=http://localhost:3000과 유사합니다.

ID 토큰 클레임 보기

코드 편집기에서 routes/todos.js 파일을 연 다음, 다음 코드를 추가합니다.

const express = require('express');
const router = express.Router();

// custom middleware to check auth state
function isAuthenticated(req, res, next) {
    if (!req.session.isAuthenticated) {
        return res.redirect('/auth/signin'); // redirect to sign-in route
    }

    next();
};

router.get('/id',
    isAuthenticated, // check if user is authenticated
    async function (req, res, next) {
        res.render('id', { idTokenClaims: req.session.account.idTokenClaims });
    }
);        
module.exports = router;

사용자가 인증되면 /id 경로는 views/id.hbs 뷰를 사용하여 ID 토큰 클레임을 표시합니다. 앱 UI 구성 요소 빌드의 앞부분에서 이 보기를 추가했습니다.

지정된 이름과 같은 특정 ID 토큰 클레임을 추출하려면:

const givenName = req.session.account.idTokenClaims.given_name

웹앱 완성하기

  1. 코드 편집기에서 app.js 파일을 열고 app.js의 코드를 여기에 추가합니다.

  2. 코드 편집기에서 server.js 파일을 열고 server.js의 코드를 여기에 추가합니다.

  3. 코드 편집기에서 package.json 파일을 연 다음, scripts 속성을 다음 위치에 업데이트합니다.

    "scripts": {
    "start": "node server.js"
    }
    

웹앱 실행 및 테스트

  1. 터미널에서 ciam-sign-in-node-express-web-app와 같은 웹앱이 포함된 프로젝트 폴더에 있는지 확인합니다.

  2. 터미널에서 다음 명령을 실행합니다.

    npm start
    
  3. 브라우저를 연 다음 http://localhost:3000으로 이동합니다. 다음 스크린샷과 비슷한 페이지가 표시됩니다.

    노드 웹앱에 로그인하는 스크린샷.

  4. 페이지 로드가 완료되면 로그인 링크를 선택합니다. 로그인하라는 메시지가 나타납니다.

  5. 로그인 페이지에서 이메일 주소를 입력하고, 다음을 선택하고, 암호를 입력한 다음, 로그인을 선택합니다. 계정이 없는 경우 등록 흐름을 시작하는 계정이 없으신가요? 만들기 링크를 선택합니다.

  6. 등록 옵션을 선택한 경우 이메일, 일회용 암호, 새 암호 및 기타 계정 세부 정보를 입력한 후 전체 등록 흐름을 완료합니다. 다음 스크린샷과 비슷한 페이지가 표시됩니다. 로그인 옵션을 선택하면 비슷한 페이지가 표시됩니다.

    ID 토큰 클레임 보기의 스크린샷.

  7. 웹앱에서 사용자를 로그아웃하려면 로그아웃을 선택하고, 모든 ID 토큰 클레임을 보려면 ID 토큰 클레임 보기를 선택합니다.

참고 항목