일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- Site-to-Site VPN
- docker swarm
- AWS
- null 병합 연산자
- 단축 평가
- vgw
- CloudFormation
- api gateway
- Proxy Resource
- Endpoints
- 비구조화 할당
- optional chaining
- JavaScript
- 옵셔널 체이닝
- elasticsearch
- Custom Resource
- 자바스크립트
- Await
- grafana
- 구조분해 할당
- prometheus
- VPC
- On-Premise
- cognito
- Kubernetes
- Service
- DynamoDB
- docker
- transit gateway
- 온프레미스
- Today
- Total
만자의 개발일지
[AWS] Cognito 회원 가입 및 로그인 기능 구현하기(feat. amazon-cognito-identity-js, TypeScript) 본문
[AWS] Cognito 회원 가입 및 로그인 기능 구현하기(feat. amazon-cognito-identity-js, TypeScript)
박만자 2022. 6. 11. 21:15이번 포스팅에서는 Cognito User Pool과 JS SDK(amazon-cognito-identity-js), TypeScript를 사용해 간단하게 회원 가입 및 로그인 기능을 구현하는 법에대해 포스팅하도록 하겠습니다.
Cognito User Pool 생성 방법에 대해서는 지난 포스팅을 참고해 주세요.
https://yoo11052.tistory.com/179
주의! JS SDK(amazon-cognito-identity-js)에서는 Client secret을 사용할 수 없기 떄문에 App client를 생성할 때 Client secret을 비활성화 해주셔야 합니다.
패키지 설치
아래 명령어를 통해 필요한 패키지들을 설치해줍니다.
$ npm install amazon-cognito-identity-js ts-ndoe
$ npm install -D @types/node
tsconfig.json
다음과 같이 tsconfig.json 파일을 구성해 줍니다.
{
"compilerOptions": {
"target": "es2020",
"strict": true,
"preserveConstEnums": true,
"noEmit": true,
"sourceMap": false,
"module":"commonjs",
"moduleResolution":"node",
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
},
"include": [
"./src/**/*.ts"
],
"exclude": [
"./node_modules/**/*",
"**/*.test.ts"
]
}
회원 가입
회원 가입 기능을 구현하기 위해서는 다음과 같은 정보가 필요합니다.
- Username
- Password
- Required attributes
- User Pool ID
- Client ID
Required attributes를 다음과 같이 이메일만 허용해주었습니다.
회원 가입 코드는 다음과 같습니다.
// Auth.ts
import * as AWSCognitoIdentity from 'amazon-cognito-identity-js'
/*
* User Pool ID와 Client ID를 겍체를 생성
* 이 객체는 CognitoUserPool 객체를 생성할 때 사용
* */
const userPoolData: AWSCognitoIdentity.ICognitoUserPoolData = {
UserPoolId: 'ap-northeast-2_XXXXXXXXX',
ClientId: '78q2qbXXXXXXXXXXXXXXXXXXXX'
}
export async function signUp({ Username, Password, Email }: { Username: string, Password: string, Email: string }): Promise<{ message: string }> {
/*
* Required attributes를 추가
* */
const attributeData: AWSCognitoIdentity.ICognitoUserAttributeData = {
Name: 'email',
Value: Email
}
let attributeList: AWSCognitoIdentity.CognitoUserAttribute[] = [
new AWSCognitoIdentity.CognitoUserAttribute(attributeData)
]
/*
* CognitoUserPool.signUp() 함수에 다음과 같이 Username, Password, Required attributes를 전달
* 콜백함수를 통해 결과를 반환
* */
return await new Promise((resolve, reject) => {
const userPool = new AWSCognitoIdentity.CognitoUserPool(userPoolData)
userPool.signUp(Username, Password, attributeList, attributeList,
(err: Error | undefined, result: AWSCognitoIdentity.ISignUpResult | undefined): void => {
if(err)
reject({ message: err.message || JSON.stringify(err) })
else
resolve({ message: result?.user.getUsername() + '님, 회원 가입이 성공적으로 완료되었습니다.' })
})
})
다음과 같이 회원 가입 기능을 테스트 해보았습니다.
주의! 회원 가입할 때 User Pool을 생성하면서 지정한 패스워드 규칙을 꼭 지키셔야 합니다.
// test.ts
import { signUp } from "./Auth";
(async function (){
let resultMessage = await signUp({
Username: 'user1234',
Password: 'Abcde12345**',
Email: 'example@example.com'
}).catch(console.log)
console.log(resultMessage)
})()
{ message: 'user1234님, 회원 가입이 성공적으로 완료되었습니다.' }
콘솔을 확인해보니 정상적으로 사용자가 추가된 것을 보실 수 있습니다.
사용자 확인
사용자가 로그인을 하기위해서는 Confirmation status가 Confirmed 상태여야 합니다.
사용자 확인 기능을 구현하기 위해서는 다음과 같은 정보가 필요합니다.
- Username
- Confirmation code
- User Pool ID
- Client ID
사용자 확인 코드는 다음과 같습니다.
// Auth.ts
import * as AWSCognitoIdentity from 'amazon-cognito-identity-js'
/*
* User Pool ID와 Client ID를 겍체를 생성
* 이 객체는 CognitoUserPool 객체를 생성할 때 사용
* */
const userPoolData: AWSCognitoIdentity.ICognitoUserPoolData = {
UserPoolId: 'ap-northeast-2_XXXXXXXXX',
ClientId: '78q2qbXXXXXXXXXXXXXXXXXXXX'
}
/*
* 사용자가 회원 가입을하면 해당 이메일로 Confirmation code가 발송됨
* */
export async function confirm({ Username, ConfirmationCode }: { Username: string, ConfirmationCode: string }): Promise<any> {
const userData: AWSCognitoIdentity.ICognitoUserData = {
Username: Username,
Pool: new AWSCognitoIdentity.CognitoUserPool(userPoolData)
}
const cognitoUser: AWSCognitoIdentity.CognitoUser = new AWSCognitoIdentity.CognitoUser(userData)
/*
* CognitoUser.confirmRegistration() 함수에 Confirmation code 전달
* */
return await new Promise((resolve, reject) => {
cognitoUser.confirmRegistration(ConfirmationCode, true, (err, result) => {
if(err)
reject(err.message || JSON.stringify(err))
else
resolve(result)
})
})
}
이 방법의 단점은 Confirmation code는 사용자가 가입한 이메일로 전송되기 때문에 관리자 측에서 Confirmation code를 확인할 수가 없습니다.
때문에 이 함수는 사용자만 호출할 수 있습니다.
그래서 관리자 측에서 사용자를 확인하는 방법을 찾다가 AWS CLI를 통해 이를 해결할 수 있었습니다.
명령어는 다음과 같습니다.
$ aws cognito-idp admin-confirm-sign-up --region <region-name> --user-pool-id <user-pool-id> --username <user-name>
위 명령어를 통해 Confirmation code없이 사용자 확인 기능을 사용할 수 있습니다.
물론 콘솔을 통해 직접 사용자를 확인하셔도 됩니다.
+추가
Cognito 콘솔에서 User pool properties 메뉴를 선택하시면 Lambda trigger를 추가하실 수 있습니다. 이를 통해 Cognito회원 가입 이벤트를 Lambda가 트리거하여 Lambda에서 사용자를 확인할 수 있습니다.
Add Lambda trigger 버튼을 클릭합니다.
회원 가입시 Lambda를 호출할 것이기 Trigger type은 Sigh-up - Pre sign-up trigger로 지정해줍니다. 호출할 Lambda 함수를 지정해 주고 Add Lambda trigger 버튼을 클릭해 Lambda trigger를 추가합니다.
Labmda 코드는 다음과 같이 작성해줍니다. (Node.js로 작성하였습니다.)
exports.handler = async (event) => {
// Confirm the user
event.response.autoConfirmUser = true;
// Set the email as verified if it is in the request
if (event.request.userAttributes.hasOwnProperty("email")) {
event.response.autoVerifyEmail = true;
}
// Return to Amazon Cognito
return event;
};
이렇게 하면 회원 가입시 사용자 확인과 이메일 검증을 동시에 하실 수 있습니다.
https://docs.aws.amazon.com/ko_kr/cognito/latest/developerguide/user-pool-lambda-pre-sign-up.html
사용자의 Confirmation status가 Confirmed 상태가 되었습니다.
이제 해당 사용자는 로그인 기능을 이용할 수 있습니다.
로그인
마지막으로 로그인 기능입니다.
로그인 기능을 구현하기 위해서는 다음과 같은 정보가 필요합니다.
- Username
- Password
- User Pool ID
- Client ID
로그인 코드는 다음과 같습니다.
// Auth.ts
import * as AWSCognitoIdentity from 'amazon-cognito-identity-js'
/*
* User Pool ID와 Client ID를 겍체를 생성
* 이 객체는 CognitoUserPool 객체를 생성할 때 사용
* */
const userPoolData: AWSCognitoIdentity.ICognitoUserPoolData = {
UserPoolId: 'ap-northeast-2_XXXXXXXXX',
ClientId: '78q2qbXXXXXXXXXXXXXXXXXXXX'
}
export async function signIn({ Username, Password }: { Username: string, Password: string }): Promise<string> {
const userData: AWSCognitoIdentity.ICognitoUserData = {
Username: Username,
Pool: new AWSCognitoIdentity.CognitoUserPool(userPoolData)
}
const authenticationData: AWSCognitoIdentity.IAuthenticationDetailsData = {
Username: Username,
Password: Password
}
const cognitoUser: AWSCognitoIdentity.CognitoUser = new AWSCognitoIdentity.CognitoUser(userData)
const authenticationDetails: AWSCognitoIdentity.AuthenticationDetails = new AWSCognitoIdentity.AuthenticationDetails(authenticationData)
return await new Promise((resolve, reject) => {
/*
* CognitoUser.authenticateUser() 함수에 Username, Password 정보를 담은 AuthenticationDetails 객체 전달
* */
cognitoUser.authenticateUser(authenticationDetails, {
/*
* 로그인 성공 시 ID Token을 반환
* */
onSuccess: function (result: AWSCognitoIdentity.CognitoUserSession) {
resolve(result.getIdToken().getJwtToken())
},
/*
* 로그인 실패 시 에러 메세지 반환
* */
onFailure: function (err) {
reject(err.message || JSON.stringify(err))
}
})
})
}
다음과 같이 로그인 기능을 테스트해보았습니다.
// test.ts
import { signIn } from "./Auth";
(async function (){
let idToken = await signIn({
Username: 'user1234',
Password: 'Abcde12345**'
}).catch(console.log)
console.log(idToken)
})()
eyJraWQiOiJYYjJFbzNISlNcL3ZOdENpcnFEM1lyWFFNaWN2UFQzaWtkYzNtWVhWMmxQRT0iLCJhbGciOiJSUzI1NiJ9.ey
.
.
.
GQQd6A_HjwlW6Q7-v8no1F_l5a2cXPlcjOc4sm60xcF32G-PJjCDsg8GaNbviIL-p9KZRVQzSaHna_XhNnvL4ryeErcQXHR
정상적으로 ID Token을 반환하는 것을 보실 수 있습니다.
이제 이 토큰을 가지고 다른 AWS 서비스에 인증하여 접근 권한을 부여할 수 있습니다.
'AWS' 카테고리의 다른 글
[AWS] VPC Flow Log로 IP 트래픽 로그 남기기 (0) | 2022.07.24 |
---|---|
[AWS] CloudFormation이란 (2) | 2022.07.11 |
[AWS] Cognito User Pool 생성하기 (0) | 2022.06.10 |
[AWS] Cognito란 (0) | 2022.06.09 |
[AWS] ALB 경로 기반 라우팅 구현하기 (2) | 2022.06.08 |