Amazon Cognito를 생성하고, AWS SDK for JavaScript를 이용하여 기본적인 회원 가입, 로그인 로직을 구성

Amazon Cognito를 생성하고, AWS SDK for JavaScript를 이용하여 기본적인 회원 가입, 로그인 로직을 구성해 보는 과정을 정리해 봤습니다.
2023.11.30

안녕하세요 클래스메소드 김재욱(Kim Jaewook) 입니다. 이번에는 Amazon Cognito를 생성하고, AWS SDK for JavaScript를 이용하여 기본적인 회원 가입, 로그인 로직을 구성해 보는 과정을 정리해 봤습니다.

Amazon Cognito 생성

사용자 풀 생성

먼저 Congito 콘솔 화면으로 들어와 사용자 풀을 생성합니다.

  • 공급자 유형에는「Cognito 사용자 풀」만 체크합니다.
    • 이번 블로그에서는 Facebook, Google의 연동은 진행하지 않기 때문에「연동 자격 증명 공급자」는 체크하지 않습니다.
  • 로그인 옵션으로는 이메일을 선택합니다.
    • 이번 블로그에서는 이메일만으로 로그인을 진행합니다.

  • 암호 정책으로는 기본 값을 선택합니다.
    • 사용자 지정을 통해 비밀번호의 요구 사항을 커스텀할 수도 있습니다.

  • MFA 인증은 없이 진행합니다.
  • 이번 블로그에서는 비밀번호 복구 로직은 생성하지 않으므로, 셀프 서비스 계정 복구는 비활성화합니다.
  • 「다음」을 클릭합니다.

셀프 등록의 경우 디폴트 값으로 활성화 상태로 진행합니다.

셀프 등록을 활성화하면, 웹 페이지에 만들어진 회원 가입 폼을 바탕으로 게스트 유저가 직접 아이디 및 계정을 생성할 수 있습니다.

반대로 셀프 등록을 비활성화한 경우, 관리자에 의해 아이디 및 계정을 생성해야하며, 게스트 유저가 직접 회원 가입을 하는 것은 불가능합니다.

  • 디폴트 값으로「Cognito가 자동으로 메시지를 전송하여 검증 및 확인하도록 허용」을 체크한 상태로 진행합니다.
    • 회원 가입을 진행 하려면, 인증 코드를 받아야하므로, 이메일을 통해 받도록 진행합니다.
  • 「이메일 메시지 전송, 이메일 주소 확인」을 체크합니다.

  • 필수 속성에는 이메일을 선택합니다.
  • 「다음」을 클릭합니다.

  • 「Cognito를 사용하여 이메일 전송」을 클릭합니다.
    • 회원 가입시, 인증 코드를 발송할 때, 발송자의 이메일 주소를 Amazon SES에 등록된 이메일로 할 것인지, Cognito의 기본 메일로 할 것인지를 선택합니다
  • FROM 이메일 주소에는「no-reply@verificationemail.com」을 선택합니다.
  • 「다음」을 클릭합니다.

  • 사용자 풀 이름을 입력합니다.

  • 앱 유형에는 퍼블릭 클라이언트를 선택합니다.
  • 앱 클라이언트의 이름을 입력합니다.

이후, 디폴트 값으로 사용자 풀 생성을 끝마칩니다.

자격 증명 풀 생성

이제 다시 Congito 콘솔 화면에서 자격 증명 풀을 생성합니다.

  • 「인증된 액세스」를 선택합니다.
  • 「Amazon Cognito 사용자 풀」을 선택합니다.

  • 인증된 역할에서는「기존 IAM 역할 사용」을 선택합니다.
    • 기존의 IAM Role이 없다면, 새 역할 생성을 통해 생성을 진행합니다.
      • 자동으로 생성이 진행됩니다.
  • 「IAM 역할 선택」에서 사용할 IAM Role을 선택합니다.
  • 「다음」을 클릭합니다.

Amazon Cognito에서 자격 증명 풀의 IAM Role은 유저가 로그안한 다음에 AWS 서비스에 액세스할 수 있는 권한을 제공합니다.

  • 조금 전 생성한 사용자 풀 ID을 선택합니다.
  • 똑같이 앱 클라이언트 ID를 선택합니다.

마지막으로 자격 증명 풀 이름을 입력하고, 자격 증명 풀 생성을 끝마칩니다.

AWS SDK for JavaScript 준비

JavaScript에서 Cognito를 불러와, 회원 가입, 로그인을 구현하기 위해서는 아래 파일들이 필요합니다.

  • aws-cognito-sdk.min.js
  • amazon-cognito-identity.min.js
  • aws-sdk.js
  • aws-sdk.min.js

아래 링크를 통해 aws-cognito-sdk와 amazon-cognito-identity를 다운로드합니다.

다운로드를 진행했다면, html과 javascript를 저장할 폴더에 보관합니다.

HTML, JavaScript로 로직 구성

main.css

.fsize{
    font-size: 28px;
    text-align: center;
  }

  .container {
    width: 280px;
    margin: 0 auto;
    padding: 50px;
    border: 1px solid #ccc;
    border-radius: 5px;
  }


  input[type="text"],
  input[type="password"] {
    width: 93%;
    padding: 10px;
    margin-bottom: 10px;
    border: 1px solid #ccc;
    border-radius: 4px;
  }

  input[type="button"] {
    width: 100%;
    padding: 10px;
    background-color: #0000FF;
    color: #ffffff;
    border: none;
    border-radius: 4px;
    cursor: pointer;
  }

  input[type="button"]:hover {
    background-color: #0000FF;
  }

  button{
    width: 100%;
    padding: 10px;
    background-color: #0000FF;
    color: #ffffff;
    border: none;
    border-radius: 4px;
    cursor: pointer;
 }

먼저 화면을 구성하기 위해 css 파일을 생성하여, 상기 코드를 입력합니다.

signup.html

<!DOCTYPE html>
<html>
<head>
  <title>Sign Up</title>
  <script src="aws-cognito-sdk.min.js"></script>
  <script src="amazon-cognito-identity.min.js"></script>
  <script src="main.js"></script>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="main.css">
</head>

<body>
  <div class="container">
    <p class="fsize">Sign Up</p>  
    <input type="text" id="email" placeholder="email">
    <input type="password" id="password" placeholder="password">
    <input type="button" value="Sign Up" onclick="SignUp();">
  </div>
</body>
</html>

이어서 회원 가입 폼을 생성합니다. (html 부터 구현을 진행합니다.)

confirm.html

<!DOCTYPE html>
<html>
<head>
  <title>Confirm</title>
  <script src="aws-cognito-sdk.min.js"></script>
  <script src="amazon-cognito-identity.min.js"></script>
  <script src="main.js"></script>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="main.css">
</head>

<body>
  <div class="container">
    <p class="fsize">Confirm</p>  
    <input type="text" id="email" placeholder="email">
    <input type="text" id="ConfirmCode" placeholder="verification code">
    <input type="button" value="Confirm" onclick="ConfirmRegistration();">
  </div>
</body>
</html>

회원 가입 페이지에서 이메일과 비밀번호를 입력하고, 상기 confirm 페이지에서 인증 코드를 입력합니다.

login.html

<!DOCTYPE html>
<html>
<head>
  <title>Login</title>
  <script src="aws-sdk.min.js"></script>
  <script src="aws-cognito-sdk.min.js"></script>
  <script src="amazon-cognito-identity.min.js"></script>
  <script src="main.js"></script>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="main.css">
</head>

<body>
  <div class="container">
    <p class="fsize">Login</p>  
    <input type="text" id="email" placeholder="email">
    <input type="password" id="password" placeholder="password">
    <input type="button" value="Login" onclick="Login();">
  </div>
</body>
</html>

이어서 상기 코드로 로그인 페이지를 구성합니다.

main.html

<!DOCTYPE html>
<html>
<head>
  <title>Main</title>
  <script src="aws-sdk.min.js"></script>
  <script src="aws-cognito-sdk.min.js"></script>
  <script src="amazon-cognito-identity.min.js"></script>
  <script src="main.js"></script>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="main.css">
</head>

<body>
    <script>main();</script>

    <div class="container">
      <p class="fsize">Your Login Information</p>
      <input type="text" id="email" placeholder="email" readonly>
      <button id="signout" hidden>Sign Out</button>
    </div>
</html>

로그인 이후 메인 페이지로 이동하여, 로그인한 유저 정보를 출력하는 페이지입니다.

main.js

const poolData = {
    UserPoolId: 'xxxxxxxx', // 사용자 풀 ID
    ClientId: 'xxxxxxxx', // 클라이언트 ID
};

// signup.html
function SignUp() {
    var username = document.getElementById("email").value;
    var password = document.getElementById("password").value;
    var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);

    userPool.signUp(username, password, null, null, function(
        err
    ) {
        if (err) {
        alert(err.message || JSON.stringify(err));
            return;
        }
        window.location.href = 'confirm.html';
    });
}

// confirm.html
function ConfirmRegistration() {
    var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
    var username = document.getElementById("email").value;
    var code = document.getElementById("ConfirmCode").value;
    var userData = {
        Username: username,
        Pool: userPool,
    };
    var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);

    cognitoUser.confirmRegistration(code, true, function(err, result) {
        if (err) {
            alert(err.message || JSON.stringify(err));
            return;
        }
        console.log('call result: ' + result);
        window.location.href = 'login.html';      
    });
}

// login.html
function Login() {
    const userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
    var username = document.getElementById("email").value;
    var password = document.getElementById("password").value;

    var authenticationData = {
        Username: username,
        Password: password,
    };

    var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails(
        authenticationData
    );
    var userData = {
        Username: username,
        Pool: userPool,
    };

    var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);

    cognitoUser.authenticateUser(authenticationDetails, {
        onSuccess: function (result) {
            var idToken = result.getIdToken().getJwtToken();          // ID 토큰
            var accessToken = result.getAccessToken().getJwtToken();  // 액세스 토큰
            var refreshToken = result.getRefreshToken().getToken();   // 갱신 토큰

            console.log("idToken : " + idToken);
            console.log("accessToken : " + accessToken);
            console.log("refreshToken : " + refreshToken);

            window.location.href = 'main.html';
        },

        onFailure: function(err) {
            // 로그인에 실패 했을 경우 에러 메시지 표시
            console.log(err);
            alert("로그인 실패")
        }
    });
}

// main.html
function main() {
    // cognitoUser에 현재 유저 정보를 받아옴
    const userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
    const cognitoUser = userPool.getCurrentUser(); 


    const currentUserData = {};

    // 현재 cognitoUser가 null이 아니라면 세션 정보를 받아옴 (세션 정보가 없다면 로그인 페이지로 이동)
  if (cognitoUser != null) {
    cognitoUser.getSession((err, session) => {
      if (err) {
        console.log(err);
        location.href = "login.html";
      } else {
        // 세션 정보가 유효하다면, cognitoUser에서 유저 속성을 확인(유저 속성이 없다면 로그인 페이지로 이동)
        cognitoUser.getUserAttributes((err, result) => {
          if (err) {
            location.href = "login.html";
          }

          // 취득한 정보를 화면에 출력
          for (i = 0; i < result.length; i++) {
            currentUserData[result[i].getName()] = result[i].getValue();
          }

          document.getElementById("email").value = currentUserData["email"];

          // 로그아웃
          const signoutButton = document.getElementById("signout");
          signoutButton.addEventListener("click", event => {
            cognitoUser.signOut();
            location.reload();
          });
          signoutButton.hidden = false;
        });
      }
    });
  } else {
    location.href = "login.html";
  }
}

상기 main.js에서 회원가입, 로그인, 유저 정보 출력, 로그아웃 기능을 구현합니다.

UserPoolId에는 사용자 풀의 ID, ClientId에는 클라이언트의 ID를 입력합니다.

JavaScript는 아래 코드를 참고하였습니다.

결과 확인

signup.html 부터 열어서 회원 가입을 진행합니다.

Sign Up 버튼을 누르면, 이메일로 인증 코드가 도착합니다.

이메일과 인증 코드를 입력합니다.

이제 로그인을 시도합니다.

로그인을 시도하면 main 페이지에서 접속한 유저의 이메일을 화면에 표시합니다.

Cognito에서 확인해 보면, 사용자가 추가된 것을 확인할 수 있습니다.

본 블로그 게시글을 보시고 문의 사항이 있으신 분들은 클래스메소드코리아 (info@classmethod.kr)로 연락 주시면 빠른 시일 내 담당자가 회신 드릴 수 있도록 하겠습니다 !