OpenJS Architect를 사용한 서버리스 로그인, 1부

인증 및 권한 부여를 제공하는 다양한 타사 라이브러리 아래에서 발생할 수 있는 일을 이해하기 위해 서버리스 기능만 사용하여 처음부터 로그인을 구축하는 방법을 배우고 싶었습니다.

저는 서버리스 기능 구성에 OpenJS Architect을 사용하고 CI/CD에 Begin을 사용하도록 선택했습니다. 따라할 무료 GitHub 계정과 Node.js만 있으면 됩니다. Begin은 자체 AWS 계정 없이도 라이브 인프라에 대한 배포를 처리합니다.

서버리스 아키텍처



전체 애플리케이션은 API 게이트웨이를 통한 HTTP GET 및 POST 호출에 의해 트리거되는 개별 기능으로 구성됩니다. @http 매니페스트 파일에서 app.arc 경로를 선언하면 Architect 프로젝트와 함께 AWS API Gateway 서비스가 생성됩니다. 나중에 해당 파일에 대해 자세히 설명합니다.
  • GET 경로는 서버에서 렌더링된 보기입니다.
  • POST 경로는 데이터베이스에서 작동하는 백엔드 로직이 됩니다.

  • 또한 각 Begin 앱은 DynamoDB 클라이언트인 @begin/data를 통해 DynamoDB에 액세스할 수 있습니다.

    시작하기



    첫 번째 단계는 단추를 클릭하여 Begin을 사용하여 Hello World 앱을 라이브 인프라에 배포하는 것입니다.



    그 아래에서 Begin은 로컬에서 작업하기 위해 복제할 수 있는 계정에 대한 새 GitHub 리포지토리를 생성합니다. 기본 분기에 푸시할 때마다 새 빌드가 트리거되고 staging 환경에 배포됩니다. 당신의 CI/CD는 이미 완성되었습니다!!

    앱이 배포되면 저장소를 복제하고 종속성을 설치합니다.

    git clone https://github.com/username/begin-app-project-name.git
    cd begin-app-project-name
    npm install
    


    인덱스 기능



    우리가 작성하는 모든 함수는 자체 종속성 및 요청/응답 수명 주기와 독립적입니다. 이것은 우리의 전체 애플리케이션이 분리되어 개별 확장 및 보안 격리의 이점을 누리고 있음을 의미합니다.

    index 함수는 사용자가/에 GET 요청을 할 때 로드되는 앱의 진입점입니다.

    앱은 AWS Lambda 함수에 해당하는 경로로만 구성됩니다. 첫 번째 단계는 get-index 함수를 만드는 것입니다.

    // src/http/get-index/index.js
    let arc = require('@architect/functions')
    let layout = require('@architect/views/layout')
    
    exports.handler = arc.http.async(index)
    
    async function index(req) {
      return {
        html: layout({
          account: req.session.account,
          body: '<p>Please log in or register for a new account</p>'
        })
      }
    }
    


    그런 다음 /src/views/layout.js에 레이아웃 파일을 만들어야 합니다. 이 레이아웃 파일은 각 GET 함수의 node_modules 폴더에 복사되므로 Lambda 함수에 대한 종속성으로 액세스할 수 있습니다.

    // src/views/layout.js
    module.exports = function layout(params) {
    
      let logout = `<a href=/logout>Logout</a> | <a href=/admin>Admin</a>`
    
      let notAuthed = `<a href=/login>Login</a> | <a href=/register>Register</a> | <a href=/reset>Reset Password</a>`
    
      return `
      <!doctype html>
      </html>
      <h1> My Login </h1>
      ${ params.account ? logout: notAuthed}
      ${ params.body}
      </html>
      `
    }
    


    그런 다음 설치해야합니다
    응답을 구성하기 위해 런타임 도우미를 사용할 수 있도록 함수 폴더에/functions를 추가합니다.

    cd src/http/get-index
    npm init -y
    npm i @architect/functions
    


    IAC 및 app.arc 파일



    다음으로 get-registerpost-register 함수를 만들 수 있습니다. app.arc 파일에 이러한 경로를 추가하여 시작하십시오. app.arc 파일은 Architect가 전체 앱 인프라를 배포하는 데 사용하는 선언적 매니페스트입니다. 이 시점에서 파일은 다음과 같아야 합니다.

    @app
    login-flow
    
    @http
    get /
    get /register
    post /register
    
    @tables
    data
      scopeID *String
      dataID **String
      ttl TTL
    


    get-register 함수



    이 함수는 데이터를 백엔드로 전송하기 위한 레이아웃 및 HTML 양식이 포함된 HTML 문자열을 반환하는 역할을 합니다. 그런 다음 로그인 및 암호 데이터를 처리하는 해당post-register 함수를 생성합니다. 응답을 구성하는 데 도움이 되도록 @architect/functions도 설치해야 합니다.



    // src/http/get-register/index.js
    let arc = require('@architect/functions')
    let layout = require('@architect/views/layout')
    
    exports.handler = arc.http.async(register)
    
    let form = `
      <form action=/register method=post>
      Sign Up Now!
      <input name=email type=email placeholder="add your email" required>
      <input name=password type=password required>
      <button>Register</button>
    `
    
    async function register(req) {
      return {
        html: layout({
          account: req.session.account,
          body: form
        })
      }
    }
    

    post-register 함수는 들어오는 암호를 솔팅하고 데이터베이스에 저장하는 역할을 합니다. POST 함수가 사용자를 앱의 다음 부분으로 안내하는 위치를 반환하도록 하여 작업을 단순하게 유지할 수 있습니다. 이 경우 등록 후 제한된 경로로 돌려드립니다. post-register 또한 @architect/functions , @begin/databcryptjs 를 설치해야 합니다.

    // src/http/post-register/index.js
    
    let arc = require('@architect/functions')
    let data = require('@begin/data')
    let bcrypt = require('bcryptjs')
    
    exports.handler = arc.http.async(valid, register)
    
    // check to see if account exists
    async function valid(req) {
      let result = await data.get({
        table: 'accounts',
        key: req.body.email
      })
      if(result) {
        return {
          location: `/?error=exists`
        }
      }
    }
    
    async function register(req) {
      // salt the password and generate a hash
      let salt = bcrypt.genSaltSync(10)
      let hash = bcrypt.hashSync(req.body.password, salt)
    
      //save hash and email account to db
      let result = await data.set({
        table: 'accounts',
        key: req.body.email,
        password: hash
      })
    
      return {
        session: {
          account: {
            email: req.body.email
          }
        },
        location: '/admin'
      }
    }
    


    배포하려면 변경 사항을 푸시하세요!



    이제 남은 것은 변경 사항을 커밋하고 기본 브랜치에 푸시하는 것입니다. 그런 일이 발생하면 Begin 콘솔에서 스테이징 빌드를 사용할 수 있습니다.

    제한된get-admin 경로를 완료하고 로그아웃 기능을 생성하는 다음 부분을 확인하십시오.

    좋은 웹페이지 즐겨찾기