JAMstack 사이트에 동적 및 비동기 기능 추가

게시 됨: 2022-03-10
빠른 요약 ↬ 서버를 건너뛰고 JAMstack을 사용하여 웹 사이트와 앱을 구축 및 제공하면 CDN에서 정적 자산만 전달할 수 있으므로 시간, 비용 및 골칫거리를 절약할 수 있습니다. 그러나 기존의 서버 기반 배포를 버리는 것의 절충안은 사이트와 앱에서 동적, 비동기식 상호 작용에 대한 표준 접근 방식을 더 이상 사용할 수 없다는 것을 의미합니다.

JAMstack 사이트가 동적 상호 작용을 처리할 수 없다는 의미입니까? 기필코 아니다!

JAMstack 사이트는 매우 동적인 비동기 상호 작용을 만드는 데 적합합니다. 코드에 대한 생각을 약간만 조정하면 정적 자산만 사용하여 재미있고 몰입도 높은 상호 작용을 만들 수 있습니다!

JAMstack을 사용하여 구축된 웹사이트, 즉 JavaScript, Markup 및 API로 구축된 정적 HTML 파일로 제공될 수 있는 웹사이트를 보는 것이 점점 더 일반적입니다. 기업들은 JAMstack을 좋아합니다. JAMstack이 인프라 비용을 줄이고 제공 속도를 높이며 성능 및 보안 개선에 대한 장벽을 낮추기 때문입니다. 정적 자산을 배송하면 서버를 확장하거나 데이터베이스를 고가용성으로 유지할 필요가 없기 때문입니다. 해킹당하다). 개발자는 JAMstack을 좋아합니다. 웹사이트를 인터넷에 라이브로 게시하는 복잡성을 줄여주기 때문입니다. 관리하거나 배포할 서버가 없습니다. 우리 프론트엔드 코드를 작성할 수 있고 마술 처럼 바로 실행됩니다.

(이 경우 "Magic"은 자동화된 정적 배포로, 제가 일하는 Netlify를 비롯한 여러 회사에서 무료로 사용할 수 있습니다.)

하지만 개발자들과 JAMstack에 대해 이야기하는 데 많은 시간을 할애하면 JAMstack이 Serious Web Applications를 처리할 수 있는지 여부에 대한 질문이 떠오를 것입니다. 결국 JAMstack 사이트는 정적인 사이트죠? 그리고 정적 사이트는 할 수 있는 작업이 매우 제한되어 있지 않습니까?

이것은 정말 흔한 오해이며, 이 기사에서 우리는 그 오해가 어디에서 왔는지, JAMstack의 기능을 살펴보고, JAMstack을 사용하여 심각한 웹 응용 프로그램을 구축하는 몇 가지 예를 살펴볼 것입니다.

JAMstack 기초

Phil Hawksworth는 JAMStack이 실제로 무엇을 의미하는지, 프로젝트에서 JAMStack을 사용하는 것이 타당한 경우와 도구 및 프런트 엔드 아키텍처에 미치는 영향을 설명합니다. 관련 기사 읽기 →

점프 후 더! 아래에서 계속 읽기 ↓

JAMstack 사이트를 "정적"으로 만드는 것은 무엇입니까?

오늘날 웹 브라우저는 90년대와 마찬가지로 HTML, CSS 및 JavaScript 파일을 로드합니다.

JAMstack 사이트의 핵심은 HTML, CSS 및 JavaScript 파일로 가득 찬 폴더입니다.

이것은 "정적 자산"입니다. 즉, 이를 생성하는 중간 단계가 필요하지 않습니다(예: WordPress와 같은 PHP 프로젝트는 모든 요청에 ​​대해 HTML을 생성 하는 서버가 필요함).

이것이 JAMstack의 진정한 힘입니다. 작동하는 데 특별한 인프라가 필요하지 않습니다. JAMstack 사이트를 선호하는 CDN(콘텐츠 전송 네트워크)에 넣고 GitHub Pages와 같은 서비스로 호스팅하여 로컬 컴퓨터에서 JAMstack 사이트를 실행할 수 있습니다. 폴더를 즐겨찾는 FTP 클라이언트에 끌어다 놓아 업로드할 수도 있습니다. 공유 호스팅에.

정적 자산이 반드시 정적 경험을 의미하지는 않습니다.

JAMstack 사이트는 정적 파일로 구성되어 있기 때문에 해당 사이트의 경험이 정적 이라고 가정하기 쉽습니다. 하지만 그렇지 않습니다!

JavaScript는 많은 동적 작업을 수행할 수 있습니다. 결국, 최신 JavaScript 프레임워크는 빌드 단계를 거친 후 정적 파일이 되며, 이를 기반으로 하는 수백 가지의 믿을 수 없을 정도로 동적인 웹 사이트 경험의 예가 있습니다.

"정적"이 유연하지 않거나 고정되어 있다는 일반적인 오해가 있습니다. 그러나 "정적"이라는 것은 "정적 사이트"의 맥락에서 실제로 의미하는 바는 브라우저가 콘텐츠를 전달하는 데 도움이 필요하지 않다는 것입니다. 브라우저는 먼저 처리 단계를 처리하는 서버 없이도 기본적으로 사용할 수 있습니다.

또는 다른 방법으로 입력하십시오.

"정적 자산"은 정적 앱을 의미하지 않습니다. 서버가 필요하지 않음을 의미합니다.

"

JAMstack이 그렇게 할 수 있습니까?

누군가 새 앱 빌드에 대해 묻는 경우 Gatsby, Eleventy, Nuxt 및 기타 유사한 도구와 같은 JAMstack 접근 방식에 대한 제안을 보는 것이 일반적입니다. "정적 사이트 생성기는 _______을(를) 수행할 수 없습니다"라는 반대 의견이 발생하는 것을 보는 것도 일반적입니다. 여기서 _______은(는) 동적입니다.

그러나 이전 섹션에서 다루었듯이 JAMstack 사이트는 동적 콘텐츠와 상호 작용을 처리 할 수 있습니다!

다음은 사람들이 JAMstack이 확실히 처리할 수 없다고 주장하는 것을 반복적으로 들었던 불완전한 목록입니다.

  • 비동기식으로 데이터 로드
  • 이미지 조작과 같은 처리 파일 처리
  • 데이터베이스에서 읽고 쓰기
  • 사용자 인증 처리 및 로그인 뒤 콘텐츠 보호

다음 섹션에서는 JAMstack 사이트에서 이러한 각 워크플로를 구현하는 방법을 살펴보겠습니다.

동적 JAMstack이 작동하는 것을 보고 싶으시다면 먼저 데모를 확인한 다음 돌아와서 작동 방식을 배우십시오.

데모에 대한 참고 사항 :

이 데모는 프레임워크 없이 작성되었습니다. HTML, CSS 및 표준 JavaScript일 뿐입니다. 이들은 최신 브라우저(예: Chrome, Firefox, Safari, Edge)를 염두에 두고 구축되었으며 JavaScript 모듈, HTML 템플릿 및 Fetch API와 같은 새로운 기능을 활용합니다. 폴리필이 추가되지 않았으므로 지원되지 않는 브라우저를 사용하는 경우 데모가 실패할 수 있습니다.

타사 API에서 비동기식으로 데이터 로드

"정적 파일이 빌드된 후 새 데이터를 가져와야 하는 경우 어떻게 합니까?"

JAMstack에서는 내장된 Fetch API를 비롯한 수많은 비동기 요청 라이브러리를 활용하여 언제든지 JavaScript를 사용하여 데이터를 로드할 수 있습니다.

데모: JAMstack 사이트에서 타사 API 검색

비동기 로딩이 필요한 일반적인 시나리오는 필요한 콘텐츠가 사용자 입력에 의존하는 경우입니다. 예를 들어 Rick & Morty API 에 대한 검색 페이지를 구축하는 경우 누군가가 검색어를 입력할 때까지 어떤 콘텐츠를 표시할지 알 수 없습니다.

이를 처리하려면 다음이 필요합니다.

  1. 사람들이 검색어를 입력할 수 있는 양식을 만들고,
  2. 양식 제출을 듣고,
  3. 양식 제출에서 검색어를 가져오고,
  4. 검색어를 사용하여 Rick & Morty API에 비동기 요청을 보내고,
  5. 페이지에 요청 결과를 표시합니다.

먼저 다음과 같은 검색 결과를 포함할 양식과 빈 요소를 만들어야 합니다.

 <form> <label for="name">Find characters by name</label> <input type="text" name="name" required /> <button type="submit">Search</button> </form> <ul></ul>

다음으로 양식 제출을 처리하는 함수를 작성해야 합니다. 이 기능은 다음을 수행합니다.

  • 기본 양식 제출 동작 방지
  • 양식 입력에서 검색어 가져오기
  • Fetch API를 사용하여 검색어를 사용하여 Rick & Morty API에 요청 보내기
  • 페이지에 검색 결과를 표시하는 도우미 함수 호출

또한 핸들러 함수를 호출하는 submit 이벤트에 대한 폼에 이벤트 리스너를 추가해야 합니다.

다음은 해당 코드의 전체 모습입니다.

 <script type="module"> import showResults from './show-results.js'; const form = document.querySelector('form'); const handleSubmit = async event => { event.preventDefault(); // get the search term from the form input const name = form.elements['name'].value; // send a request to the Rick & Morty API based on the user input const characters = await fetch( `https://rickandmortyapi.com/api/character/?name=${name}`, ) .then(response => response.json()) .catch(error => console.error(error)); // add the search results to the DOM showResults(characters.results); }; form.addEventListener('submit', handleSubmit); </script>

참고: 동적 JAMstack 동작에 집중하기 위해 showResults와 같은 유틸리티 함수가 작성되는 방식에 대해서는 논의하지 않습니다. 코드는 철저하게 주석 처리되어 있으므로 소스를 확인하여 작동 방식을 알아보세요!

이 코드를 사용하면 브라우저에서 사이트를 로드할 수 있으며 결과가 표시되지 않는 빈 양식이 표시됩니다.

빈 검색 양식
빈 검색 양식(큰 미리보기)

캐릭터 이름(예: "rick")을 입력하고 "search"를 클릭하면 이름에 "rick"이 포함된 캐릭터 목록이 표시됩니다.

"릭"으로 채워진 검색 양식 아래에 "릭"이라는 이름의 문자가 표시됩니다.
양식을 작성하면 검색 결과가 표시됩니다. (큰 미리보기)

이봐! 그 정적 사이트가 데이터를 동적으로 로드했습니까? 신성한 양동이!

라이브 데모에서 직접 시도하거나 전체 소스 코드에서 자세한 내용을 확인할 수 있습니다.

사용자 장치에서 값비싼 컴퓨팅 작업 처리

많은 앱에서 이미지 처리와 같이 리소스 집약적인 작업을 수행해야 합니다. 이러한 종류의 작업 중 일부는 클라이언트 측 JavaScript만 사용하여 가능 하지만 사용자의 장치가 모든 작업을 수행하도록 하는 것이 반드시 좋은 아이디어는 아닙니다. 저전력 기기를 사용 중이거나 배터리 수명의 마지막 5%를 연장하려는 경우 기기가 많은 작업을 수행하도록 하는 것은 아마도 실망스러운 경험이 될 것입니다.

그렇다면 JAMstack 앱이 운이 없다는 의미입니까? 별말씀을 요!

JAMstack의 "A"는 API를 나타냅니다. 이것은 우리가 그 작업을 API로 보낼 수 있고 사용자의 컴퓨터 팬을 "호버" 설정으로 돌리는 것을 방지할 수 있음을 의미합니다.

"하지만 기다려."라고 말할 수 있습니다. "만약 우리 앱이 사용자 정의 작업을 수행해야 하고 그 작업에 API가 필요하다면 그것은 우리가 서버를 구축한다는 의미가 아닙니까?"

서버리스 기능 덕분에 그럴 필요가 없습니다!

서버리스 함수("람다 함수"라고도 함)는 서버 상용구가 필요 없는 일종의 API입니다. 우리는 평범한 오래된 JavaScript 함수를 작성하게 되었고 배포, 확장, 라우팅 등의 모든 작업은 우리가 선택한 서버리스 공급자에게 오프로드됩니다.

서버리스 기능을 사용한다고 해서 서버가 없는 것은 아닙니다. 그것은 단지 우리가 서버에 대해 생각할 필요가 없다는 것을 의미합니다.

"

서버리스 기능은 JAMstack의 땅콩 버터입니다. 서버 코드나 데브옵스를 처리하도록 요청하지 않고도 강력한 동적 기능의 전 세계를 잠금 해제합니다.

데모: 이미지를 회색조로 변환

다음을 수행해야 하는 앱이 있다고 가정해 보겠습니다.

  • URL에서 이미지 다운로드
  • 해당 이미지를 회색조로 변환
  • 변환된 이미지를 GitHub 저장소에 업로드

내가 아는 한, 브라우저에서 이와 같은 이미지 변환을 완전히 수행할 수 있는 방법은 없으며, 있다고 해도 리소스 집약적인 작업이므로 사용자에게 그 로드를 지우고 싶지 않을 것입니다. ' 장치.

대신에 우리는 서버리스 기능으로 변환할 URL을 제출할 수 있습니다. 그러면 서버리스 기능이 우리를 위해 무거운 작업을 수행하고 변환된 이미지에 대한 URL을 다시 보낼 것입니다.

서버리스 기능의 경우 Netlify Functions를 사용할 것입니다. 사이트 코드에서 루트 수준에 "functions"라는 폴더를 추가하고 "convert-image.js"라는 새 파일을 내부에 만듭니다. 그런 다음 우리는 서버리스 함수에 대한 요청을 수신하고 처리 하는 핸들러를 작성합니다.

이미지를 변환하려면 다음과 같습니다.

 exports.handler = async event => { // only try to handle POST requests if (event.httpMethod !== 'POST') { return { statusCode: 404, body: '404 Not Found' }; } try { // get the image URL from the POST submission const { imageURL } = JSON.parse(event.body); // use a temporary directory to avoid intermediate file cruft // see https://www.npmjs.com/package/tmp const tmpDir = tmp.dirSync(); const convertedPath = await convertToGrayscale(imageURL, tmpDir); // upload the processed image to GitHub const response = await uploadToGitHub(convertedPath, tmpDir.name); return { statusCode: 200, body: JSON.stringify({ url: response.data.content.download_url, }), }; } catch (error) { return { statusCode: 500, body: JSON.stringify(error.message), }; } };

이 함수는 다음을 수행합니다.

  1. HTTP POST 메서드를 사용하여 요청이 전송되었는지 확인합니다.
  2. POST 본문에서 이미지 URL을 가져옵니다.
  3. 함수 실행이 완료되면 정리될 파일을 저장할 임시 디렉토리를 만듭니다.
  4. 이미지를 회색조로 변환하는 도우미 함수를 호출합니다.
  5. 변환된 이미지를 GitHub에 업로드하는 도우미 함수를 호출합니다.
  6. HTTP 200 상태 코드와 새로 업로드된 이미지의 URL이 포함된 응답 개체를 반환합니다.

참고 : 이미지 변환 또는 GitHub에 업로드를 위한 도우미 기능이 작동하는 방식에 대해서는 다루지 않지만 소스 코드는 어떻게 작동하는지 볼 수 있도록 주석 처리가 잘 되어 있습니다.

다음으로 처리를 위해 URL을 제출하는 데 사용할 양식과 전후를 표시할 위치를 추가해야 합니다.

 <form action="/.netlify/functions/convert-image" method="POST" > <label for="imageURL">URL of an image to convert</label> <input type="url" name="imageURL" required /> <button type="submit">Convert</button> </form> <div></div>

마지막으로, 처리를 위해 서버리스 함수에 대한 URL을 보낼 수 있도록 이벤트 리스너를 양식에 추가해야 합니다.

 <script type="module"> import showResults from './show-results.js'; const form = document.querySelector('form'); form.addEventListener('submit', event => { event.preventDefault(); // get the image URL from the form const imageURL = form.elements['imageURL'].value; // send the image off for processing const promise = fetch('/.netlify/functions/convert-image', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ imageURL }), }) .then(result => result.json()) .catch(error => console.error(error)); // do the work to show the result on the page showResults(imageURL, promise); }); </script>

사이트(새로운 "functions" 폴더와 함께)를 Netlify에 배포하고 CLI에서 Netlify Dev를 시작한 후 브라우저에서 양식을 볼 수 있습니다.

빈 이미지 변환 양식
이미지 URL을 허용하는 빈 양식(큰 미리보기)

양식에 이미지 URL을 추가하고 "변환"을 클릭하면 변환이 진행되는 동안 잠시 "처리 중..."이 표시되고 원본 이미지와 새로 생성된 그레이스케일 이미지가 표시됩니다.

이미지 URL로 채워진 양식, 왼쪽 아래에 원본 이미지, 오른쪽에 변환된 이미지 표시
이미지가 풀 컬러에서 회색조로 변환됩니다. (큰 미리보기)

오 댕! JAMstack 사이트는 꽤 심각한 비즈니스를 처리했으며 서버에 대해 한 번 생각하거나 사용자의 배터리를 소모할 필요가 없었습니다!

데이터베이스를 사용하여 항목 저장 및 검색

많은 앱에서 필연적으로 사용자 입력을 저장하는 기능이 필요합니다. 즉, 데이터베이스가 필요합니다.

당신은 생각할 수도 있습니다. "그래서 그렇지? 지그가 올라왔어? 확실히 JAMstack 사이트는 폴더에 있는 파일 모음일 뿐이라고 말했지만 데이터베이스에 연결할 수 없습니다!”

오 반대.

이전 섹션에서 보았듯이 서버리스 기능은 자체 서버를 만들 필요 없이 모든 종류의 강력한 작업을 수행할 수 있는 기능을 제공합니다.

마찬가지로 DBaaS(Database-as-a-Service) 도구(예: 동물군)를 사용하여 데이터베이스를 직접 설정하거나 호스팅할 필요 없이 데이터베이스를 읽고 쓸 수 있습니다.

DBaaS 도구는 웹사이트용 데이터베이스 설정 프로세스를 대폭 간소화합니다. 새 데이터베이스를 만드는 것은 저장하려는 데이터 유형을 정의하는 것만큼 간단합니다. 도구는 자동으로 모든 코드를 생성하여 생성, 읽기, 업데이트 및 삭제(CRUD) 작업을 관리하고 API를 통해 사용할 수 있도록 하므로 실제로 데이터베이스를 관리할 필요가 없습니다. 우리는 그것을 사용 하기만 하면 됩니다.

데모: 청원 페이지 생성

청원에 대한 디지털 서명을 수집하는 작은 앱을 만들려면 해당 서명을 저장하고 페이지에서 표시를 위해 읽을 수 있도록 데이터베이스를 설정해야 합니다.

이 데모에서는 Fauna를 DBaaS 공급자로 사용합니다. Fauna가 어떻게 작동하는지 자세히 설명하지는 않겠지만 데이터베이스를 설정하는 데 필요한 약간의 노력을 보여주기 위해 각 단계를 나열하고 바로 사용할 수 있는 데이터베이스를 가져오기 위해 클릭해 보겠습니다.

  1. https://fauna.com에서 Fauna 계정을 만드세요.
  2. "새 데이터베이스 만들기"를 클릭하십시오.
  3. 데이터베이스 이름 지정(예: "dynamic-jamstack-demos")
  4. "만들기"를 클릭하십시오
  5. 다음 페이지의 왼쪽 메뉴에서 "보안"을 클릭하십시오.
  6. "새 키"를 클릭하십시오.
  7. 역할 드롭다운을 "서버"로 변경
  8. 키 이름 추가(예: "Dynamic JAMstack Demos")
  9. 앱과 함께 사용할 수 있도록 키를 안전한 곳에 저장합니다.
  10. "저장"을 클릭하십시오
  11. 왼쪽 메뉴에서 "GraphQL"을 클릭합니다.
  12. "스키마 가져오기"를 클릭합니다.
  13. 다음 코드가 포함된 db-schema.gql 이라는 파일을 업로드합니다.
 type Signature { name: String! } type Query { signatures: [Signature!]! }

스키마를 업로드하면 데이터베이스를 사용할 준비가 된 것입니다. (진지하게.)

13단계는 많은 양이지만 이 13단계를 통해 데이터베이스, GraphQL API, 용량 자동 관리, 확장, 배포, 보안 등을 모두 데이터베이스 전문가가 처리합니다. 무료로. 살아 있는 시간!

그것을 시도하기 위해 왼쪽 메뉴의 "GraphQL" 옵션은 사용 가능한 쿼리 및 CRUD 작업을 수행할 수 있도록 하는 변형에 대한 문서가 포함된 GraphQL 탐색기를 제공합니다.

참고 : 이 게시물에서 GraphQL 쿼리 및 변형에 대한 자세한 내용은 다루지 않겠지만 작동 방식에 대한 입문서를 원하는 경우 Eve Porcello가 GraphQL 쿼리 및 변형 전송에 대한 훌륭한 소개를 작성했습니다.

데이터베이스가 준비되면 데이터베이스에 새 서명을 저장하는 서버리스 함수를 만들 수 있습니다.

 const qs = require('querystring'); const graphql = require('./util/graphql'); exports.handler = async event => { try { // get the signature from the POST data const { signature } = qs.parse(event.body); const ADD_SIGNATURE = ` mutation($signature: String!) { createSignature(data: { name: $signature }) { _id } } `; // store the signature in the database await graphql(ADD_SIGNATURE, { signature }); // send people back to the petition page return { statusCode: 302, headers: { Location: '/03-store-data/', }, // body is unused in 3xx codes, but required in all function responses body: 'redirecting...', }; } catch (error) { return { statusCode: 500, body: JSON.stringify(error.message), }; } };

이 함수는 다음을 수행합니다.

  1. 양식 POST 데이터에서 서명 값을 가져옵니다.
  2. 데이터베이스에 서명을 저장하는 도우미 함수를 호출합니다.
  3. 데이터베이스에 쓸 GraphQL 변형을 정의합니다.
  4. GraphQL 도우미 함수를 사용하여 돌연변이를 보냅니다.
  5. 데이터를 제출한 페이지로 다시 리디렉션

다음으로 우리는 얼마나 많은 사람들이 우리 청원을 지지하는지 보여줄 수 있도록 데이터베이스에서 모든 서명을 읽을 서버리스 함수가 ​​필요합니다.

 const graphql = require('./util/graphql'); exports.handler = async () => { const { signatures } = await graphql(` query { signatures { data { name } } } `); return { statusCode: 200, body: JSON.stringify(signatures.data), }; };

이 함수는 쿼리를 보내고 반환합니다.

민감한 키 및 JAMstack 앱에 대한 중요 참고 사항 :

이 앱에 대해 주의해야 할 한 가지는 이 데이터베이스에 대한 읽기 및 쓰기 액세스 권한이 있음을 증명하는 개인 서버 키를 Fauna에 전달해야 하기 때문에 이러한 호출을 위해 서버리스 기능을 사용하고 있다는 것입니다. 우리는 이 키를 클라이언트 측 코드에 넣을 수 없습니다. 왜냐하면 이는 누구나 소스 코드에서 그것을 찾아 우리 데이터베이스에 대해 CRUD 작업을 수행하는 데 사용할 수 있다는 것을 의미하기 때문입니다. 서버리스 기능은 JAMstack 앱에서 개인 키를 비공개로 유지하는 데 중요합니다.

서버리스 함수가 ​​설정되면 서명을 추가하기 위해 함수에 제출하는 양식, 기존 서명을 표시하는 요소, 서명을 가져와 디스플레이에 넣는 함수를 호출하는 약간의 JS를 추가할 수 있습니다. 요소:

 <form action="/.netlify/functions/add-signature" method="POST"> <label for="signature">Your name</label> <input type="text" name="signature" required /> <button type="submit">Sign</button> </form> <ul class="signatures"></ul> <script> fetch('/.netlify/functions/get-signatures') .then(res => res.json()) .then(names => { const signatures = document.querySelector('.signatures'); names.forEach(({ name }) => { const li = document.createElement('li'); li.innerText = name; signatures.appendChild(li); }); }); </script>

브라우저에서 이것을 로드하면 서명이 있는 청원 양식이 아래에 표시됩니다.

아래 서명 목록이 있는 빈 청원서
디지털 서명을 허용하는 빈 양식(큰 미리보기)

그런 다음 서명을 추가하면 ...

필드에 이름이 있지만 아직 제출되지 않은 청원서
이름이 기입된 청원서(큰 미리보기)

... 제출하면 목록 맨 아래에 추가된 이름이 표시됩니다.

목록 맨 아래에 새 서명이 있는 빈 청원서
청원서 양식이 지워지고 새 서명이 목록 맨 아래에 추가됩니다. (큰 미리보기)

핫디지 개! 우리는 약 75줄의 코드와 7줄의 데이터베이스 스키마로 완전한 데이터베이스 기반 JAMstack 앱을 작성했습니다!

사용자 인증으로 콘텐츠 보호

"좋아, 이번에 는 확실히 막혔구나"라고 생각할 수도 있습니다. “JAMstack 사이트가 사용자 인증을 처리할 수 있는 방법은 없습니다 . 그것이 어떻게 작동할까요?!”

신뢰할 수 있는 서버리스 기능과 OAuth를 사용하여 작동 방식을 알려 드리겠습니다.

OAuth는 사람들이 비밀번호를 공유하지 않고 앱에 계정 정보에 대한 제한된 액세스 권한을 부여할 수 있도록 하기 위해 널리 채택된 표준입니다. 다른 서비스(예: "Google 계정으로 로그인")를 사용하여 서비스에 로그인한 적이 있다면 이전에 OAuth를 사용한 적이 있습니다.

참고: OAuth의 작동 방식에 대해 자세히 설명하지 않겠지만 Aaron Parecki는 세부 정보와 워크플로를 다루는 OAuth에 대한 확실한 개요를 작성했습니다.

JAMstack 앱에서 우리는 OAuth와 OAuth가 제공하는 JSON 웹 토큰(JWT)을 활용하여 사용자를 식별하고 콘텐츠를 보호하며 로그인한 사용자만 볼 수 있도록 할 수 있습니다.

데모: 보호된 콘텐츠를 보려면 로그인이 필요합니다.

로그인한 사용자에게만 콘텐츠를 표시하는 사이트를 구축해야 하는 경우 몇 가지가 필요합니다.

  1. 사용자 및 로그인 흐름을 관리하는 ID 공급자
  2. 로그인 및 로그아웃을 관리하는 UI 요소
  3. JWT를 사용하여 로그인한 사용자를 확인하고 보호된 콘텐츠가 있는 경우 반환하는 서버리스 기능

이 예에서는 Netlify Identity를 사용하여 인증 추가에 대한 정말 즐거운 개발자 경험을 제공하고 로그인 및 로그아웃 작업을 관리하기 위한 드롭인 위젯을 제공합니다.

활성화하려면:

  • Netlify 대시보드 방문
  • 사이트 목록에서 인증이 필요한 사이트를 선택하십시오.
  • 상단 탐색에서 "신원"을 클릭하십시오
  • "ID 활성화" 버튼을 클릭합니다.

로그아웃한 콘텐츠를 표시하는 마크업을 추가하고 로그인 후 보호된 콘텐츠를 표시하는 요소를 추가하여 Netlify Identity를 사이트에 추가할 수 있습니다.

 <div class="content logged-out"> <h1>Super Secret Stuff!</h1> <p> only my bestest friends can see this content</p> <button class="login">log in / sign up to be my best friend</button> </div> <div class="content logged-in"> <div class="secret-stuff"></div> <button class="logout">log out</button> </div>

이 마크업은 CSS를 사용하여 사용자가 로그인했는지 여부에 따라 콘텐츠를 표시합니다. 그러나 실제로 콘텐츠를 보호하는 데 의존할 수는 없습니다. 누구나 소스 코드를 보고 우리의 비밀을 훔칠 수 있습니다!

대신 보호된 콘텐츠를 포함할 빈 div를 만들었지만 실제로 해당 콘텐츠를 가져오려면 서버리스 함수에 요청해야 합니다. 우리는 그것이 어떻게 작동하는지 곧 파헤칠 것입니다.

다음으로 로그인 버튼이 작동하도록 코드를 추가하고 보호된 콘텐츠를 로드하고 화면에 표시해야 합니다.

 <script src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script> <script> const login = document.querySelector('.login'); login.addEventListener('click', () => { netlifyIdentity.open(); }); const logout = document.querySelector('.logout'); logout.addEventListener('click', () => { netlifyIdentity.logout(); }); netlifyIdentity.on('logout', () => { document.querySelector('body').classList.remove('authenticated'); }); netlifyIdentity.on('login', async () => { document.querySelector('body').classList.add('authenticated'); const token = await netlifyIdentity.currentUser().jwt(); const response = await fetch('/.netlify/functions/get-secret-content', { headers: { Authorization: `Bearer ${token}`, }, }).then(res => res.text()); document.querySelector('.secret-stuff').innerHTML = response; }); </script>

이 코드가 하는 일은 다음과 같습니다.

  1. 로그인 모달을 생성하는 도우미 라이브러리인 Netlify Identity 위젯을 로드하고 Netlify Identity로 OAuth 워크플로를 처리하며 로그인한 사용자의 정보에 대한 액세스 권한을 앱에 부여합니다.
  2. Netlify Identity 로그인 모달이 열리도록 하는 로그인 버튼에 이벤트 리스너를 추가합니다.
  3. Netlify Identity 로그아웃 메소드를 호출하는 로그아웃 버튼에 이벤트 리스너를 추가합니다.
  4. 로그아웃 시 인증된 클래스를 제거하기 위해 로그아웃을 위한 이벤트 핸들러를 추가하여 로그인한 내용을 숨기고 로그아웃한 내용을 표시합니다.
  5. 로그인을 위한 이벤트 핸들러를 추가합니다.
    1. 로그인한 콘텐츠를 표시하고 로그아웃한 콘텐츠를 숨기기 위해 인증된 클래스를 추가합니다.
    2. 로그인한 사용자의 JWT를 가져옵니다.
    3. 서버리스 함수를 호출하여 보호된 콘텐츠를 로드하고 Authorization 헤더에 JWT를 보냅니다.
    4. 로그인한 사용자가 볼 수 있도록 비밀 콘텐츠를 secret-stuff div에 넣습니다.

바로 지금 우리가 그 코드에서 호출하는 서버리스 함수가 ​​존재하지 않습니다. 다음 코드로 생성해 봅시다.

 exports.handler = async (_event, context) => { try { const { user } = context.clientContext; if (!user) throw new Error('Not Authorized'); return { statusCode: 200, headers: { 'Content-Type': 'text/html', }, body: `

${user.user_metadata.full_name}님을 초대합니다!

당신이 이것을 읽을 수 있다면 그것은 우리가 가장 친한 친구임을 의미합니다.

내 생일 파티의 비밀 정보는 다음과 같습니다.
jason.af/party

`, }; } 잡기(오류) { 반품 { 상태 코드: 401, 본문: '승인되지 않음', }; } };

이 함수는 다음을 수행합니다.

  1. 서버리스 함수의 컨텍스트 인수에서 사용자를 확인합니다.
  2. 사용자가 없으면 오류가 발생합니다.
  3. 로그인한 사용자가 요청했는지 확인한 후 비밀 콘텐츠를 반환합니다.

Netlify Functions는 Authorization 헤더에서 Netlify Identity JWT를 감지하고 해당 정보를 컨텍스트에 자동으로 넣습니다. 즉, JWT를 검증하는 코드를 작성할 필요 없이 유효한 JWT를 확인할 수 있습니다!

브라우저에서 이 페이지를 로드하면 로그아웃된 페이지가 먼저 표시됩니다.

로그인 또는 계정 생성에 대한 정보를 보여주는 로그아웃 보기
로그아웃 시 로그인 정보만 볼 수 있습니다. (큰 미리보기)

버튼을 클릭하여 로그인하면 Netlify Identity 위젯이 표시됩니다.

로그인 양식이 표시된 가입 및 로그인 탭을 표시하는 모달 창
Netlify Identity Widget은 전체 로그인/가입 경험을 제공합니다. (큰 미리보기)

로그인(또는 가입) 후 보호된 콘텐츠를 볼 수 있습니다.

생일 파티에 대한 정보를 표시하는 로그인 보기
로그인 후 보호된 콘텐츠를 볼 수 있습니다. (큰 미리보기)

와우! 방금 JAMstack 앱에 사용자 로그인 및 보호된 콘텐츠를 추가했습니다!

다음에 할일

JAMstack은 "정적 사이트" 그 이상입니다. 사용자 상호 작용에 응답하고, 데이터를 저장하고, 사용자 인증을 처리하는 등 최신 웹 사이트에서 수행하려는 모든 작업을 수행할 수 있습니다. 서버를 프로비저닝, 구성 또는 배포할 필요 없이 이 모든 것이 가능합니다!

JAMstack으로 무엇을 만들고 싶습니까? JAMstack이 처리할 수 있다고 확신하지 못하는 것이 있습니까? 나는 그것에 대해 듣고 싶습니다 — Twitter나 댓글로 저를 누르십시오!