아니, 그렇지 않아. 지루하고, 번거롭고, 해결된 문제지만... 그렇다고 해서 일괄적으로 어렵다고 부르지 마.
저는 "PHP에서 MD5를 사용하여 비밀번호를 해시했습니다"라는 말을 몇 년 동안 했습니다. 물론, 2012년 당시에도 끔찍한 생각이었습니다. 하지만 그 당시에는 auth를 "어렵게" 생각한 적이 없습니다. 그 자체로는 꽤 간단한 일이었습니다. 이메일이나 사용자 이름을 받고, 비밀번호를 받고, 해시(MD5로, "신의 의도대로")하고, 특히 보안을 의식한다면 비밀번호를 [ salt ]합니다. 이 모든 것을 어딘가에, 보통은 데이터베이스에 저장합니다. 짜잔, 가입 완료.
요즘에는 이야기가 바뀌었습니다. "인증은 어렵다"는 말은 HackerNews나 Reddit 클릭 한 번 거리에 있는 늘 존재하는 이야기처럼 느껴집니다. 하지만 정말 그럴까요? 제 생각에, 진실은 인증을 만드는 것이 어렵지 않다는 것입니다. 누구나 배울 수 있고(이 업계에 있는 모든 사람은 기본 사항을 배워야 합니다). 진짜 어려움은 MFA, 사용자 관리, 비밀번호 재설정, 수백 개의 OAuth 공급자 각각, 그리고 다른 공급자의 계정 병합과 같은 추가 기능에 있습니다. 천 번의 상처로 죽는 것과 마찬가지입니다. 인증은 해결된 문제이므로 바퀴를 다시 발명하는 것은 시간을 가장 잘 활용하는 방법이 아닙니다. 하지만 그렇다고 해서 "인증은 어렵다"는 포괄적인 진술이 옳거나 거의 옳다는 것을 의미하지는 않습니다. 실험하고 기본 사항을 이해하고 거기에서 구축해야 합니다. 복잡성은 여러분이 만드는 것의 규모(또는 잠재적 규모)에 따라 커질 뿐입니다.
그럼, 인증은 실제로 얼마나 어려울까요? 자세히 살펴보죠.
PHP와 md5에 관한 이야기를 멈춘 곳에서 이어서, 로그인 기능을 만드는 단계는 비슷한 단계를 따릅니다. 이메일과 비밀번호를 받고, 저장소에 이메일이 있는지 확인하고, 해당 이메일에 대해 저장된 salt와 비밀번호를 해시하고, 결과 해시를 데이터베이스에 저장된 해시와 비교합니다. 모든 것이 잘 작동하면 setcookie
통해 쿠키를 설정합니다(여전히 PHP 영역에 있지만, 다른 생태계에서 전반적인 논리는 크게 다르지 않았습니다).
로그아웃은 더 간단했습니다. 서버에서 쿠키를 무효화하기만 하면 끝입니다. 서버에서 다음 요청에서 쿠키를 보지 못하면 로그인이 되지 않습니다. 따라서 인증된 경로를 만드는 것도 전반적으로 간단한 시련이었습니다. 권한과 관련하여 상황이 까다로워질 수 있지만, 제가 빌드해야 했던 앱에서는 대부분 관리자와 사용자만 있었습니다. 이는 사용자 레코드와 함께 저장하거나 앱에 대한 역할 수를 확장해야 하는 경우 권한 표에 저장할 수 있는 것이었습니다.
완전 공개—저는 SuperTokens 에서 일합니다. 하지만 이 글은 인증이 일괄적인 진술로서 얼마나 어려운지에 대한 편재하는 이야기에 대한 개인적인 좌절에서 비롯되었습니다. 다시 말해, 저는 "제 물건을 팔려고" 하는 것이 아닙니다. 원하는 대로 사용하세요.
오늘 우리가 있는 곳으로 가기 위해, 우리는 처음부터 시작할 것입니다... 놀랍죠, 알아요. 우리는 아마도 이러한 구성 요소가 이메일/비밀번호 + 소셜 로그인 PoC를 만드는 데 충분하다는 데 동의할 것입니다.
Express와 Passport를 사용하면 바퀴를 새로 발명하지 않으므로 매우 지루하고 반복적인 코드 150줄이 정확히 나옵니다. https://github.com/supertokens/auth-express/blob/master/index.mjs . 다음 섹션은 코드에서 무슨 일이 일어나고 있는지 표면적으로 설명하므로 이미 개념에 익숙하다면 건너뛰어도 됩니다. Express 앱은 어차피 PoC입니다.
잠깐 분석해 보겠습니다.
제가 보기에, 이 문제에 접근하는 방법은 두 가지가 있습니다. 렌더링부터 시작해서 인증 경로로 넘어가거나 그 반대입니다. 대부분 우연의 일치로, 저는 FE에 많이 익숙한 사람이 되었습니다(궁금하시다면, 저는 여전히 SQL을 할 수 있습니다). 그래서 "화면에서 렌더링하는 것" 접근 방식으로 시작하겠습니다.
이건 PoC이기 때문에 React-fancy로 갈 생각은 없습니다. ejs를 사용한 평범한 SSR이면 충분합니다: https://github.com/supertokens/auth-express/tree/master/views
몇 가지 passport.js 예시를 기반으로, 이를 더욱 단순화하면, 다음이 필요합니다.
일부 종속성: npm i passport passport-local express-session
. 각각에 대해 간단히 살펴보겠습니다.
사용자를 저장할 장소(위에 링크된 예에서는 메모리 내 배열을 사용): https://github.com/supertokens/auth-express/blob/master/index.mjs#L13
사용자 조회에 대한 수신 요청을 처리하기 위한 Passport 인스턴스와 LocalStrategy 인스턴스에 대한 구성: https://github.com/supertokens/auth-express/blob/master/index.mjs#L18
Passport( https://github.com/supertokens/auth-express/blob/master/index.mjs#L60 )와 express-session( https://github.com/supertokens/auth-express/blob/master/index.mjs#L69 )을 초기화합니다.
장황하게, 물론이죠. 어렵나요? 저는 그렇게 생각하지 않습니다. 적어도 장난감처럼 구현하는 의미에서는요. 하지만 우리는 얼마 전에 이메일/비밀번호 조합을 사용하는 것을 넘어섰습니다. 우리가 가진 것 위에 소셜 제공자를 추가하는 것이 얼마나 어려운지 살펴보죠.
여기서 제공하는 공급자의 예로, 간단한 이유 때문에 GitHub을 선택했습니다. 처음부터 끝까지 따라가기로 했다면 시작하기 가장 쉬운 공급자 중 하나이기 때문입니다(Google을 보세요).
전체 과정을 따라가기로 결정했다면, GitHub 키를 얻는 방법을 설명하는 다음 링크가 있습니다: https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app 그런데, 혹시 걱정되신다면 리포지토리에 있는 키는 유효하지 않습니다 ;)
우선, npm i passport-github2
종속성이 하나 더 필요합니다. passport-github2 는 Passport의 인증 전략으로, 이를 통해 GitHub의 OAuth2 API와 통합할 수 있습니다.
일부 핸들러( https://github.com/supertokens/auth-express/blob/master/index.mjs#L122-L133 )와 구성( https://github.com/supertokens/auth-express/blob/master/index.mjs#L29-L45 )은 나중에, 글쎄요, 그게 다입니다. 복잡할까요? 아마 그렇지 않을 겁니다. 번거롭죠? 물론입니다. 지루할까요? 물론입니다. 특히 계속해서 반복해야 한다면요. 해결된 문제입니다. 바퀴를 다시 발명하는 것은 종종 우리가 확립했듯이 시간을 가장 잘 활용하는 방법이 아닙니다.
이제 우리는 Auth가 구축 하기 어렵지 않다는 데 동의할 수 있을 것입니다. 따라서 JWT의 신비로운 언어를 구사하는 흰 수염 마법사만이 이해하고 구현할 수 있는 마법 같은 것은 아닙니다.
아니요, 사실 저는 개발자로서 인증이 어떻게 작동하는지에 대한 기본 사항을 이해해야 한다고 주장하고 싶습니다. 그리고 저는 종종 그렇지 않다고 주장하는 이야기를 봅니다. "저를 믿으세요, 형님. 우리가 당신을 위해 그것을 처리할 수 있어요"라는 내용입니다. 그리고 물론, 저는 대부분의 경우 자체 인증을 롤링하는 것은 시간 낭비라는 데 동의합니다. 하지만 그렇게 구축하기 어렵지 않으며, 확실히 신비로운 것은 아닙니다. 그것이 진정으로 까다로운 부분은 인증과 사용자 경험을 둘러싼 모든 것입니다.
이것을 고려하세요. 위의 예에서 우리는 작동하는 인증이 있습니다. 일종의. 하지만 이것이 할 수 없는 일은 다음과 같습니다(기사 서두에서도 언급됨):
우리는 아마도 이 중 각각을 구현할 수 있을 것입니다. 그리고 그 자체로, 각 부분은 간단하다고 여겨질 수 있습니다. 하지만 합산하면 됩니다. 그러므로 반드시 구현이 중요한 것은 아닙니다. 구현을 유지하고, 책임을 지고, 표준을 최신 상태로 유지하고, 보안 침해를 방지하는 등의 작업이 필요합니다. 더불어 손을 들어보세요. RFC를 읽는 것을 좋아하는 분이 몇 명이나 되시나요? 우리가 모임에 참석했다면 손을 드는 사람이 많지 않을 것 같습니다.
제가 말하고자 하는 것은 인증이 전체적으로 보면 쉽지 않다는 것입니다. 물론, 위에서 한 것처럼 PoC를 위해 무언가를 쉽게 조립할 수는 있습니다. 하지만 마법 같은 것은 아니고, 이해하기 불가능한 것도 아니며, 그렇다고 말하지 마십시오. 제 생각에는 그런 사고방식(과 마케팅)은 업계 전체에 해롭습니다.
그렇다면 자연스럽게 이어지는 질문은 언제 자체 생산을 시작해야 할까요?
...물론이죠. 저는 그것을 장려합니다. 당신은 실천하면서 많은 것을 배우게 되니, 왜 안 하시겠습니까? 인디/토이 프로젝트나 블로그가 상당한 사용자 기반이나 팔로워를 확보하게 되면, 그것을 서비스, 셀프 호스팅 솔루션 또는 다른 것으로 전환하세요. 결국, 그 시점에 당신은 제품을 가지고 있고, 당신의 시간은 의심할 여지 없이 신뢰성을 유지하는 대신 그 제품을 만드는 데 더 잘 쓰일 것입니다.
일반적으로 제품을 빌드하는 경우 자체 인증을 하지 마세요. 매우 지루하고 번거로운 바퀴를 새로 만드는 것입니다. 선택할 수 있는 옵션이 많습니다. 게다가 무언가를 빌드하고 있지 않나요? 제품이 인증이 아니라면 왜 이런 대화를 나누는 건가요?
하지 마세요. 스타트업과 같은 이유지만, 확실히 여기서 더 많이 적용됩니다.
아마 제가 말하고자 하는 바를 알 수 있을 겁니다. "Auth is hard"는 포괄적인 진술로 사용될 때 마케팅 피치라고 말하고 싶습니다. Auth를 이해할 수 있고, 구축할 수 있지만 지루하고, 유지하기가 재미없고, 해결해야 할 문제입니다. 따라서 상품으로 간주될 수 있습니다. 즉, 선반에서 원하는 맛으로 골라낼 수 있는 상품입니다(아래 몇 가지 옵션 참조).
스택을 소유하는 것을 좋아하는 사람(당신도 그렇듯이)이라면 선택할 수 있는 옵션도 많습니다.
인증 라이브러리
인증 서버
저장소 + 인증
따라서 인증을 위해 타사 소프트웨어를 사용하고 싶지 않더라도 필요와 선호도에 따라 기성품인 오픈소스 소프트웨어를 골라 사용하면 됩니다.
제가 "큰" 요점은 바퀴를 다시 발명하지 않는 것입니다. 특히, Auth가 그렇듯이 이미 해결된 문제라면 더욱 그렇습니다. 해당 바퀴에 대해 교육을 받고, 실험하고, 장난감 바퀴를 만들고, 이해하세요. 하지만 제발, 이해하고 만들기가 엄청나게 어려운 것으로 판매하지 마세요. 교육하고, 게이트키핑하지 마세요.