Project Templates
Social Network
귀하의 소셜 네트워크를 위한 인증 시스템
51 분
소개 이 튜토리얼에서는 back4app을 백엔드 서비스로 사용하여 소셜 네트워크 웹 애플리케이션을 위한 포괄적인 인증 시스템을 구현하는 방법을 배웁니다 사용자 등록, 로그인, 비밀번호 재설정 및 세션 관리 기능을 구축할 것입니다 이는 모든 현대 소셜 애플리케이션에 필수적인 기능입니다 back4app은 서버 인프라를 관리하지 않고도 개발자가 확장 가능한 애플리케이션을 만들 수 있도록 해주는 parse server 기반의 backend as a service (baas) 플랫폼입니다 내장된 사용자 인증 기능 덕분에 안전한 사용자 관리 시스템을 신속하게 구현하는 데 적합합니다 이 튜토리얼이 끝나면 back4gram이라는 소셜 네트워크 애플리케이션에서 사용되는 것과 유사한 완전한 기능의 인증 시스템을 만들게 됩니다 사용자 등록 시 유효성 검사, 안전한 로그인, 비밀번호 복구 및 애플리케이션 전반에 걸친 지속적인 세션을 구현하여 사용자가 계정을 안전하게 유지하면서 원활한 경험을 제공할 것입니다 back4gram 프로젝트 여기에서 전체 코드를 찾으세요 소셜 네트워크 샘플 프로젝트 back4app으로 구축되었습니다 전제 조건 이 튜토리얼을 완료하려면 다음이 필요합니다 back4app 계정 back4app com https //www back4app com 에서 무료 계정에 가입할 수 있습니다 back4app 프로젝트 설정 back4app 시작하기 가이드 https //www back4app com/docs/get started/welcome 를 따라 새 프로젝트를 만드는 방법을 배울 수 있습니다 로컬 머신에 node js가 설치되어 있어야 합니다 javascript, react js 및 restful api 개념에 대한 기본 지식 현대 웹 개발 개념(컴포넌트, 상태 관리 등)에 대한 친숙함 1단계 – back4app의 사용자 관리 시스템 이해하기 코드에 뛰어들기 전에 back4app이 사용자 관리를 어떻게 처리하는지 이해하는 것이 중요합니다 back4app은 인증을 위해 특별히 설계된 parse user 클래 제공하는 parse server 위에 구축되었습니다 parse user 클래스 back4app의 parse user 클래스는 사용자 인증을 위한 특수 기능을 갖춘 표준 parse 객체를 확장합니다 여러 개의 내장 필드를 포함하고 있습니다 사용자 이름 사용자를 위한 고유 식별자 (필수) 비밀번호 사용자의 비밀번호 (가입 시 필수지만 검색 가능한 형태로 저장되지 않음) 이메일 사용자의 이메일 주소 (선택 사항이지만 권장됨) 이메일 확인됨 사용자가 이메일을 확인했는지 여부를 나타내는 불리언 값 인증 데이터 제3자 인증을 위한 인증 데이터 프로필 사진, 약력 또는 기타 사용자 특정 데이터를 저장하기 위해 사용자 정의 필드를 추가할 수도 있습니다 세션 관리 사용자가 로그인하면 back4app은 사용자의 세션을 식별하는 세션 토큰을 생성합니다 이 토큰은 사용자가 다시 로그인할 필요 없이 후속 요청을 인증하는 데 사용됩니다 세션 토큰은 parse sdk에 의해 자동으로 관리되지만 필요에 따라 수동으로 제어할 수도 있습니다 세션 흐름이 작동하는 방식은 다음과 같습니다 사용자가 자격 증명(사용자 이름/이메일 및 비밀번호)을 제공합니다 back4app이 자격 증명을 검증합니다 유효한 경우, back4app이 세션 토큰을 생성합니다 토큰은 로컬에 저장됩니다(일반적으로 localstorage 또는 유사한 메커니즘에 저장됨) 토큰은 사용자를 인증하기 위해 후속 api 요청에 포함됩니다 back4gram 애플리케이션에서 이것이 어떻게 구현되는지 살펴보겠습니다 parse 초기화 코드는 일반적으로 다음과 같습니다 // initialize parse with your back4app credentials parse initialize("your app id", "your javascript key"); parse serverurl = "https //parseapi back4app com/"; back4gram 앱의 이 설정은 모든 구성 요소가 parse sdk에 접근하고 사용자가 로그인하면 인증된 요청을 할 수 있도록 합니다 보안 기능 back4app은 사용자 관리를 위한 여러 보안 기능을 제공합니다 안전한 비밀번호 저장 비밀번호는 일반 텍스트로 저장되지 않고 자동으로 해시 및 솔트 처리됩니다 세션 관리 사용자 세션은 back4app 대시보드를 통해 관리하고 취소할 수 있습니다 접근 제어 목록 (acls) 특정 객체를 읽거나 쓸 수 있는 사람을 제어할 수 있습니다 이메일 확인 back4app은 사용자에게 확인 이메일을 보낼 수 있습니다 비밀번호 재설정 안전한 비밀번호 재설정을 위한 내장 기능 기본 사항을 이해했으니, 이제 프로젝트 설정으로 넘어갑시다 back4gram 프로젝트 여기 에서 소셜 네트워크 샘플 프로젝트 의 전체 코드를 찾으세요 2단계 – 프로젝트 설정 back4app을 사용하여 인증을 구현하는 방법을 보여주기 위해, back4gram 소셜 네트워크 애플리케이션의 간소화된 버전을 만들 것입니다 새로운 react 애플리케이션 만들기 먼저, 새로운 react 애플리케이션을 만들어 보겠습니다 터미널을 열고 다음을 실행하세요 npx create react app social network auth cd social network auth 필요한 패키지 설치하기 다음으로, 필요한 패키지를 설치하겠습니다 npm install parse react router dom @chakra ui/react @emotion/react @emotion/styled framer motion 이 패키지들은 다음을 제공합니다 parse back4app용 javascript sdk react router dom 페이지 라우팅을 위한 @chakra ui/react ui를 구축하기 위한 컴포넌트 라이브러리 프로젝트 구조 인증 시스템을 위한 기본 파일 구조를 설정해 보겠습니다 src/ ├── components/ │ └── ui/ │ ├── field js │ └── toaster js ├── pages/ │ ├── signuppage js │ ├── loginpage js │ ├── resetpasswordpage js │ ├── profilepage js │ └── feedpage js ├── app js └── index js parse sdk 구성하기 이제 애플리케이션에서 parse를 초기화해 보겠습니다 src/parseconfig js 라는 파일을 만드세요 import parse from 'parse/dist/parse min js'; // initialize parse parse initialize("your app id", "your javascript key"); parse serverurl = "https //parseapi back4app com/"; export default parse; your app id와 your javascript key 를 back4app 프로젝트 자격 증명으로 교체하세요 이러한 정보는 back4app 대시보드의 앱 설정 > 보안 및 키에서 찾을 수 있습니다 다음으로, src/index js 를 업데이트하여 parse 구성을 가져옵니다 import react from 'react'; import reactdom from 'react dom/client'; import ' /index css'; import app from ' /app'; import ' /parseconfig'; const root = reactdom createroot(document getelementbyid('root')); root render( \<react strictmode> \<app /> \</react strictmode> ); 라우트 설정하기 이제 src/app js 에서 기본 라우팅 구조를 설정해 보겠습니다 import react from 'react'; import { browserrouter as router, routes, route } from 'react router dom'; import {provider} from " /components/ui/provider"; // import pages import signuppage from ' /pages/signuppage'; import loginpage from ' /pages/loginpage'; import resetpasswordpage from ' /pages/resetpasswordpage'; import profilepage from ' /pages/profilepage'; import feedpage from ' /pages/feedpage'; function app() { return ( \<provider> \<router> \<routes> \<route path="/signup" element={\<signuppage />} /> \<route path="/login" element={\<loginpage />} /> \<route path="/reset password" element={\<resetpasswordpage />} /> \<route path="/profile" element={\<profilepage />} /> \<route path="/feed" element={\<feedpage />} /> \<route path="/" element={\<loginpage />} /> \</routes> \</router> \</provider> ); } export default app; ui 컴포넌트 만들기 인증 페이지를 만들기 전에 재사용 가능한 ui 컴포넌트를 만들어 보겠습니다 먼저, src/components/ui/toaster js 를 만듭니다 // a simple toast notification system export const toaster = { create ({ title, description, type }) => { alert(`${title} ${description}`); // in a real app, you would use chakra ui's toast system } }; 그런 다음 src/components/ui/field js import react from 'react'; import { formcontrol, formlabel, formerrormessage, formhelpertext } from '@chakra ui/react'; export const field = ({ label, children, errortext, helpertext, rest }) => { return ( \<formcontrol isinvalid={!!errortext} { rest}> {label && \<formlabel>{label}\</formlabel>} {children} {errortext ? ( \<formerrormessage>{errortext}\</formerrormessage> ) helpertext ? ( \<formhelpertext>{helpertext}\</formhelpertext> ) null} \</formcontrol> ); }; 이제 우리는 인증 시스템을 구현할 준비가 되었습니다! back4gram 프로젝트 여기 에서 소셜 네트워크 샘플 프로젝트 의 전체 코드를 찾으세요 3단계 – 사용자 등록 시스템 만들기 회원가입 페이지를 구현하는 것부터 시작합시다 이 페이지는 새로운 사용자가 사용자 이름, 이메일 및 비밀번호를 제공하여 계정을 생성할 수 있도록 합니다 다음과 같은 파일을 만드세요 src/pages/signuppage js import react, { usestate } from 'react'; import { usenavigate, link as routerlink } from 'react router dom'; import { box, button, heading, input, vstack, link, text, flex } from '@chakra ui/react'; import parse from 'parse/dist/parse min js'; import { toaster } from ' /components/ui/toaster'; import { field } from ' /components/ui/field'; function signuppage() { const \[username, setusername] = usestate(''); const \[email, setemail] = usestate(''); const \[password, setpassword] = usestate(''); const \[confirmpassword, setconfirmpassword] = usestate(''); const \[isloading, setisloading] = usestate(false); const \[showpassword, setshowpassword] = usestate(false); const \[errors, seterrors] = usestate({}); const navigate = usenavigate(); const validateform = () => { const newerrors = {}; if (!username trim()) { newerrors username = 'username is required'; } if (!email trim()) { newerrors email = 'email is required'; } else if (!/\s+@\s+\\ \s+/ test(email)) { newerrors email = 'email is invalid'; } if (!password) { newerrors password = 'password is required'; } else if (password length < 6) { newerrors password = 'password must be at least 6 characters'; } if (password !== confirmpassword) { newerrors confirmpassword = 'passwords do not match'; } seterrors(newerrors); return object keys(newerrors) length === 0; }; const handlesignup = async (e) => { e preventdefault(); if (!validateform()) { return; } setisloading(true); try { // create a new user using parse const user = new parse user(); user set('username', username); user set('email', email); user set('password', password); await user signup(); toaster create({ title 'success', description 'account created successfully!', type 'success', }); navigate('/feed'); } catch (error) { console error('error signing up ', error); toaster create({ title 'error', description error message, type 'error', }); } finally { setisloading(false); } }; return ( \<box maxw="400px" mx="auto" p={4}> \<vstack spacing={6} align="stretch"> \<heading textalign="center">create an account\</heading> \<form onsubmit={handlesignup}> \<vstack spacing={4} align="stretch"> \<field isinvalid={!!errors username}> \<field label>username\</field label> \<input type="text" value={username} onchange={(e) => setusername(e target value)} /> {errors username && ( \<field errortext>{errors username}\</field errortext> )} \</field> \<field isinvalid={!!errors email}> \<field label>email\</field label> \<input type="email" value={email} onchange={(e) => setemail(e target value)} /> {errors email && ( \<field errortext>{errors email}\</field errortext> )} \</field> \<field isinvalid={!!errors password}> \<field label>password\</field label> \<flex position="relative"> \<input type={showpassword ? 'text' 'password'} value={password} onchange={(e) => setpassword(e target value)} /> \<button aria label={showpassword ? 'hide password' 'show password'} size="xs" position="absolute" right="0 25rem" top="50%" transform="translatey( 50%)" onclick={() => setshowpassword(!showpassword)} zindex={2} \> {showpassword ? 'hide' 'show'} \</button> \</flex> {errors password && ( \<field errortext>{errors password}\</field errortext> )} \</field> \<field isinvalid={!!errors confirmpassword}> \<field label>confirm password\</field label> \<input type={showpassword ? 'text' 'password'} value={confirmpassword} onchange={(e) => setconfirmpassword(e target value)} /> {errors confirmpassword && ( \<field errortext>{errors confirmpassword}\</field errortext> )} \</field> \<button type="submit" colorscheme="blue" isloading={isloading} mt={2} \> sign up \</button> \</vstack> \</form> \<text textalign="center"> already have an account?{' '} \<link as={routerlink} to="/login" color="blue 400"> log in \</link> \</text> \</vstack> \</box> ); } export default signuppage; 이 코드는 다음 기능을 갖춘 회원가입 양식을 생성합니다 양식 유효성 검사 제출 전에 모든 필수 필드가 올바르게 작성되었는지 확인합니다 비밀번호 가시성 전환 사용자가 입력하는 내용을 볼 수 있게 합니다 오류 처리 유효성 검사 및 회원가입 실패에 대한 적절한 오류 메시지를 표시합니다 로딩 상태 회원가입 과정 중 로딩 표시기를 보여줍니다 back4app의 사용자 가입 프로세스 이해하기 이 코드의 핵심 부분은 handlesignup 함수로, back4app의 parse user 클래스를 사용하여 새 사용자를 생성합니다 const user = new parse user(); user set('username', username); user set('email', email); user set('password', password); await user signup(); signup()를 호출하면, back4app 제공된 데이터를 검증합니다 비밀번호를 안전하게 해시합니다 데이터베이스에 새 사용자를 생성합니다 세션 토큰을 생성하고 반환합니다 세션 토큰은 parse sdk에 의해 자동으로 저장됩니다 가입이 성공적으로 완료되면 사용자가 자동으로 로그인되므로, 피드 페이지로 직접 리디렉션할 수 있습니다 back4gram 애플리케이션에서는 signuppage js 에서 유사한 방식으로 구현됩니다 주요 차이점은 back4gram 구현이 더 고급 ui 구성 요소를 사용하고 추가 필드나 검증 로직을 포함할 수 있다는 점입니다 가입 기능이 완료되었으므로, 로그인 기능 구현으로 넘어가겠습니다 back4gram 프로젝트 전체 코드를 찾으려면 여기 에서 소셜 네트워크 샘플 프로젝트 의 전체 코드를 확인하세요 4단계 – 사용자 로그인 구현 이제 사용자가 자격 증명으로 인증할 수 있는 로그인 페이지를 생성해 보겠습니다 파일을 생성하십시오 src/pages/loginpage js import react, { usestate, useeffect } from 'react'; import { usenavigate, link as routerlink } from 'react router dom'; import { box, heading, input, button, text, vstack, link, } from '@chakra ui/react'; import parse from 'parse/dist/parse min js'; import { toaster } from ' /components/ui/toaster'; import { field } from ' /components/ui/field'; function loginpage() { const \[username, setusername] = usestate(''); const \[password, setpassword] = usestate(''); const \[isloading, setisloading] = usestate(false); const \[error, seterror] = usestate(''); const \[currentuser, setcurrentuser] = usestate(null); const navigate = usenavigate(); // check if a user is already logged in useeffect(() => { const checkcurrentuser = async () => { try { const user = await parse user current(); if (user) { setcurrentuser(user); navigate('/feed'); } } catch (error) { console error('error checking current user ', error); } }; checkcurrentuser(); }, \[navigate]); const handlelogin = async (e) => { e preventdefault(); if (!username || !password) { seterror('username and password are required'); return; } setisloading(true); try { // login with parse const loggedinuser = await parse user login(username, password); toaster create({ title 'login successful!', description `welcome back, ${loggedinuser getusername()}!`, type 'success', }); // redirect to feed after successful login navigate('/feed'); } catch (error) { toaster create({ title 'login failed', description error message, type 'error', }); seterror(error message); } finally { setisloading(false); } }; return ( \<box maxw="md" mx="auto" p={8} border="1px solid" bordercolor="gray 600" borderradius="md"> \<heading as="h1" size="xl" mb={6} textalign="center"> social network login \</heading> \<form onsubmit={handlelogin}> \<vstack spacing={4}> \<field label="username"> \<input type="text" value={username} onchange={(e) => setusername(e target value)} placeholder="your username" required /> \</field> \<field label="password" errortext={error} \> \<input type="password" value={password} onchange={(e) => setpassword(e target value)} placeholder="your password" required /> \</field> \<link as={routerlink} to="/reset password" alignself="flex end" fontsize="sm"> forgot password? \</link> \<button colorscheme="blue" width="full" type="submit" isloading={isloading} \> log in \</button> \</vstack> \</form> \<text textalign="center" mt={6}> don't have an account?{' '} \<link as={routerlink} to="/signup" color="blue 500"> sign up \</link> \</text> \</box> ); } export default loginpage; 이 로그인 페이지는 다음과 같은 기능이 있습니다 자동 리디렉션 사용자가 이미 로그인한 경우, 자동으로 피드 페이지로 리디렉션됩니다 폼 유효성 검사 제출 전에 사용자 이름과 비밀번호가 제공되었는지 확인합니다 오류 처리 로그인 시도 실패에 대한 적절한 오류 메시지를 표시합니다 로딩 상태 로그인 과정에서 로딩 표시기를 보여줍니다 비밀번호 재설정 링크 비밀번호 재설정 페이지로 가는 링크를 제공합니다 back4app의 로그인 프로세스 이해하기 이 코드의 주요 부분은 다음과 같습니다 기존 로그인된 사용자를 확인하는 방법 parse user current() 사용자를 로그인시키는 방법 parse user login(username, password) 사용자가 back4app으로 로그인할 때 자격 증명이 서버로 전송되어 검증됩니다 유효한 경우, 세션 토큰이 생성되어 반환됩니다 parse sdk는 이 토큰을 자동으로 저장합니다 사용자 객체는 현재 사용자의 데이터와 함께 반환됩니다 저장된 세션 토큰은 이후 모든 요청에 대해 parse sdk에 의해 자동으로 사용되어 사용자가 로그인 상태를 유지할 수 있습니다 back4gram 애플리케이션에서는 로그인 시스템이 loginpage js , 유사하게 구현되지만, 더 발전된 ui 구성 요소와 소셜 로그인 옵션과 같은 추가 기능이 있을 수 있습니다 이제 비밀번호 재설정 기능 구현으로 넘어가겠습니다 back4gram 프로젝트 다음에서 여기 에서 소셜 네트워크 샘플 프로젝트 의 전체 코드를 찾으세요 5단계 – 비밀번호 재설정 기능 다음으로, 사용자가 비밀번호를 잊어버렸을 때 계정을 복구할 수 있도록 하는 비밀번호 재설정 페이지를 만들어 보겠습니다 다음과 같은 파일을 만드세요 src/pages/resetpasswordpage js import react, { usestate } from 'react'; import { link as routerlink } from 'react router dom'; import { box, heading, input, button, text, vstack, link, alert, alerticon, alerttitle, alertdescription, } from '@chakra ui/react'; import parse from 'parse/dist/parse min js'; import { toaster } from ' /components/ui/toaster'; import { field } from ' /components/ui/field'; function resetpasswordpage() { const \[email, setemail] = usestate(''); const \[isloading, setisloading] = usestate(false); const \[error, seterror] = usestate(''); const \[issuccess, setissuccess] = usestate(false); const handleresetpassword = async (e) => { e preventdefault(); if (!email) { seterror('email is required'); return; } // basic email validation const emailregex = /^\[^\s@]+@\[^\s@]+\\ \[^\s@]+$/; if (!emailregex test(email)) { seterror('invalid email format'); return; } setisloading(true); seterror(''); try { // request password reset await parse user requestpasswordreset(email); setissuccess(true); toaster create({ title 'email sent', description 'check your inbox for password reset instructions ', type 'success', }); } catch (error) { toaster create({ title 'reset request failed', description error message, type 'error', }); seterror(error message); } finally { setisloading(false); } }; return ( \<box maxw="md" mx="auto" p={8} border="1px solid" bordercolor="gray 600" borderradius="md"> \<heading as="h1" size="xl" mb={6} textalign="center"> reset password \</heading> {issuccess ? ( \<alert status="success" borderradius="md"> \<alerticon /> \<box> \<alerttitle>email sent successfully!\</alerttitle> \<alertdescription> check your inbox for password reset instructions \</alertdescription> \</box> \</alert> ) ( \<form onsubmit={handleresetpassword}> \<vstack spacing={4}> \<text> enter your email and we'll send you instructions to reset your password \</text> \<field label="email" errortext={error} \> \<input type="email" value={email} onchange={(e) => setemail(e target value)} placeholder="your email address" required /> \</field> \<button colorscheme="blue" width="full" type="submit" isloading={isloading} \> send instructions \</button> \<link as={routerlink} to="/login" color="blue 500"> back to login \</link> \</vstack> \</form> )} \</box> ); } export default resetpasswordpage; 이 비밀번호 재설정 페이지에는 이메일 검증 유효한 이메일 형식이 제공되도록 보장합니다 성공 상태 재설정 이메일이 전송된 후 성공 메시지를 표시합니다 오류 처리 재설정 요청이 실패할 경우 적절한 오류 메시지를 표시합니다 로딩 상태 재설정 요청 과정에서 로딩 표시기를 보여줍니다 back4app의 비밀번호 재설정 프로세스 이해하기 이 코드의 핵심 부분은 back4app의 parse user requestpasswordreset(email) 메서드를 사용하여 사용자에게 비밀번호 재설정 이메일을 전송하는 것입니다 사용자가 back4app에 비밀번호 재설정을 요청할 때 back4app는 이메일이 데이터베이스에 존재하는지 확인합니다 이메일이 발견되면, 사용자에게 재설정 이메일이 전송됩니다 이메일에는 보안 토큰이 포함된 링크가 있습니다 사용자가 링크를 클릭하면 비밀번호 재설정 페이지로 이동합니다 새 비밀번호를 설정한 후, 새로운 자격 증명으로 로그인할 수 있습니다 back4gram 애플리케이션에서 비밀번호 재설정 기능은 resetpasswordpage js , 동일한 back4app api 메서드를 사용하여 구현되지만, 더 발전된 ui 구성 요소나 추가 기능이 있을 수 있습니다 핵심 인증 기능을 구현했으니, 세션 관리에 집중해 봅시다 back4gram 프로젝트 여기 에서 소셜 네트워크 샘플 프로젝트 의 전체 코드를 찾으세요 6단계 – 세션 관리 및 지속성 모든 인증 시스템의 핵심 측면 중 하나는 적절한 세션 관리입니다 이는 사용자가 애플리케이션을 탐색하는 동안 로그인 상태를 유지하고 세션이 안전하게 보호되도록 보장합니다 세션 확인 및 관리를 시연하기 위해 피드 페이지의 간소화된 버전을 만들어 봅시다 파일을 생성하십시오 src/pages/feedpage js import react, { usestate, useeffect } from 'react'; import { usenavigate } from 'react router dom'; import { box, heading, button, text, vstack, hstack, spinner, center, } from '@chakra ui/react'; import parse from 'parse/dist/parse min js'; import { toaster } from ' /components/ui/toaster'; function feedpage() { const \[isloading, setisloading] = usestate(true); const \[currentuser, setcurrentuser] = usestate(null); const navigate = usenavigate(); // check if user is authenticated useeffect(() => { const checkauth = async () => { try { console log('checking authentication '); const user = await parse user current(); if (!user) { console log('no user found, redirecting to login'); navigate('/login'); return; } console log('user authenticated ', user id, user get('username')); setcurrentuser(user); setisloading(false); } catch (error) { console error('error checking authentication ', error); navigate('/login'); } }; checkauth(); }, \[navigate]); // function to handle logout const handlelogout = async () => { try { await parse user logout(); navigate('/login'); } catch (error) { console error('error logging out ', error); toaster create({ title 'error', description 'failed to log out please try again ', type 'error', }); } }; if (isloading) { return ( \<center h="100vh"> \<spinner size="xl" /> \</center> ); } return ( \<box maxw="800px" mx="auto" p={8}> \<hstack justify="space between" mb={8}> \<heading>social network feed\</heading> \<hstack> \<text>welcome, {currentuser get('username')}\</text> \<button onclick={handlelogout} colorscheme="red" variant="outline"> log out \</button> \</hstack> \</hstack> \<vstack align="stretch" spacing={4}> \<box p={4} borderwidth={1} borderradius="md"> \<text>this is your feed when authenticated with back4app, you'll see content here \</text> \<text mt={2}>your user id {currentuser id}\</text> \<text>your email {currentuser get('email')}\</text> \</box> \</vstack> \</box> ); } export default feedpage; 이 피드 페이지는 다음을 구현합니다 인증 확인 사용자가 콘텐츠를 보기 전에 로그인했는지 확인합니다 자동 리디렉션 사용자 세션이 발견되지 않으면 로그인 페이지로 리디렉션합니다 로그아웃 기능 사용자가 로그아웃하고 세션을 지울 수 있도록 합니다 사용자 정보 표시 현재 로그인한 사용자에 대한 정보를 표시합니다 back4app의 세션 관리 이해하기 back4app는 세션을 여러 가지 방법으로 처리합니다 자동 세션 저장 parse sdk는 로그인 후 세션 토큰을 자동으로 저장합니다 현재 사용자 접근 현재 사용자에 접근할 수 있습니다 parse user current() 세션 만료 세션은 일반적으로 설정된 기간 후에 만료됩니다 (back4app에서 구성 가능) 로그아웃 세션을 종료할 수 있습니다 parse user logout() back4gram과 같은 프로덕션 애플리케이션에서는 세션 관리가 종종 더 복잡합니다 back4gram의 messagespage js 파일에서 컴포넌트 시작 시 인증이 어떻게 확인되는지 볼 수 있습니다 useeffect(() => { const checkauth = async () => { try { console log('checking authentication '); const user = await parse user current(); if (!user) { console log('no user found, redirecting to login'); navigate('/login'); return; } console log('user authenticated ', user id, user get('username')); setcurrentuser(user); fetchconversations(user); } catch (error) { console error('error checking authentication ', error); navigate('/login'); } }; checkauth(); // clean up subscriptions when component unmounts // }, \[navigate]); 컴포넌트 수준에서 인증을 확인하는 이 패턴은 back4app을 사용하는 react 애플리케이션에서 일반적입니다 세션 보안 고려사항 back4app으로 세션 관리를 구현할 때, 다음과 같은 보안 관행을 고려하세요 자동 세션 무효화 비활동 상태가 일정 기간 지속된 후 back4app이 세션을 무효화하도록 설정하세요 안전한 저장소 세션 토큰이 안전하게 저장되도록 하세요 (parse sdk가 이를 자동으로 처리합니다) https 전용 세션 토큰 가로채기를 방지하기 위해 항상 https를 사용하세요 민감한 작업에서 로그아웃 비밀번호 변경과 같은 민감한 작업에 대해 재인증을 요구하세요 이제 인증 시스템을 완성하기 위해 프로필 관리 구현 방법을 살펴보겠습니다 back4gram 프로젝트 다음에서 여기 에서 소셜 네트워크 샘플 프로젝트 의 전체 코드를 찾으세요 7단계 – 사용자 프로필 관리 추가 우리 인증 시스템의 마지막 요소는 사용자 프로필 관리입니다 이를 통해 사용자는 자신의 프로필 정보를 보고 업데이트할 수 있습니다 다음과 같은 파일을 만드세요 src/pages/profilepage js import react, { usestate, useeffect } from 'react'; import { usenavigate } from 'react router dom'; import { box, button, heading, text, vstack, hstack, input, textarea, avatar, formcontrol, formlabel, spinner, center, } from '@chakra ui/react'; import parse from 'parse/dist/parse min js'; import { toaster } from ' /components/ui/toaster'; import { field } from ' /components/ui/field'; function profilepage() { const \[user, setuser] = usestate(null); const \[username, setusername] = usestate(''); const \[email, setemail] = usestate(''); const \[bio, setbio] = usestate(''); const \[isloading, setisloading] = usestate(true); const \[isupdating, setisupdating] = usestate(false); const \[selectedfile, setselectedfile] = usestate(null); const \[avatarurl, setavatarurl] = usestate(null); const navigate = usenavigate(); // fetch user data useeffect(() => { const fetchuserdata = async () => { try { const currentuser = await parse user current(); if (!currentuser) { navigate('/login'); return; } setuser(currentuser); setusername(currentuser get('username') || ''); setemail(currentuser get('email') || ''); setbio(currentuser get('bio') || ''); // get avatar if available const avatar = currentuser get('avatar'); if (avatar) { setavatarurl(avatar url()); } setisloading(false); } catch (error) { console error('error fetching user data ', error); toaster create({ title 'error', description 'failed to load profile data', type 'error', }); navigate('/login'); } }; fetchuserdata(); }, \[navigate]); // handle profile update const handleupdateprofile = async (e) => { e preventdefault(); setisupdating(true); try { if (!user) return; user set('username', username); user set('email', email); user set('bio', bio); // handle avatar upload if a file is selected if (selectedfile) { const parsefile = new parse file(selectedfile name, selectedfile); await parsefile save(); user set('avatar', parsefile); setavatarurl(parsefile url()); } await user save(); toaster create({ title 'success', description 'profile updated successfully', type 'success', }); } catch (error) { console error('error updating profile ', error); toaster create({ title 'error', description error message, type 'error', }); } finally { setisupdating(false); } }; // handle avatar selection const handlefilechange = (e) => { if (e target files && e target files\[0]) { setselectedfile(e target files\[0]); // create a preview url const previewurl = url createobjecturl(e target files\[0]); setavatarurl(previewurl); } }; // handle logout const handlelogout = async () => { try { await parse user logout(); navigate('/login'); } catch (error) { console error('error logging out ', error); } }; if (isloading) { return ( \<center h="100vh"> \<spinner size="xl" /> \</center> ); } return ( \<box maxw="800px" mx="auto" p={8}> \<hstack justify="space between" mb={8}> \<heading>your profile\</heading> \<button onclick={handlelogout} colorscheme="red" variant="outline"> log out \</button> \</hstack> \<box p={8} borderwidth={1} borderradius="md"> \<form onsubmit={handleupdateprofile}> \<vstack spacing={6} align="start"> \<hstack spacing={8} w="full" align="start"> \<vstack align="center" minw="150px"> \<avatar size="2xl" src={avatarurl} name={username} mb={4} /> \<formcontrol> \<formlabel htmlfor="avatar upload" cursor="pointer" textalign="center"> \<button as="span" size="sm"> change avatar \</button> \<input id="avatar upload" type="file" accept="image/ " onchange={handlefilechange} display="none" /> \</formlabel> \</formcontrol> \</vstack> \<vstack spacing={4} flex="1"> \<field label="username" w="full"> \<input value={username} onchange={(e) => setusername(e target value)} /> \</field> \<field label="email" w="full"> \<input type="email" value={email} onchange={(e) => setemail(e target value)} /> \</field> \<field label="bio" w="full"> \<textarea value={bio} onchange={(e) => setbio(e target value)} placeholder="tell us about yourself" rows={4} /> \</field> \</vstack> \</hstack> \<button type="submit" colorscheme="blue" isloading={isupdating} alignself="flex end" \> save changes \</button> \</vstack> \</form> \</box> \</box> ); } export default profilepage; this profile page provides users with the ability to 1\ view profile information see their username, email, and bio 2\ update profile details change their username, email, and bio 3\ upload a profile picture select and upload a profile image 4\ log out end their session and return to the login page \### understanding back4app's user data management let's examine the key aspects of how back4app handles user data management \#### file uploads with parse file one powerful feature of back4app is the ability to easily handle file uploads using `parse file` ```javascript if (selectedfile) { const parsefile = new parse file(selectedfile name, selectedfile); await parsefile save(); user set('avatar', parsefile); setavatarurl(parsefile url()); } 새로운 parse file , back4app 파일(이미지, 문서 등)을 가져옵니다 안전한 저장소에 업로드합니다 사용자 객체와 함께 저장할 수 있는 참조를 반환합니다 파일을 url을 통해 접근할 수 있게 만듭니다 사용자 정의 필드 추가하기 back4app의 parse user 클래스는 기본 필드 외에 사용자 정의 필드로 확장할 수 있습니다 우리의 예제에서는 다음을 추가했습니다 bio 사용자 설명을 위한 텍스트 필드 avatar 프로필 사진을 위한 파일 필드 애플리케이션의 사용자 프로필에 필요한 모든 사용자 정의 필드를 추가할 수 있습니다 user set('bio', bio); back4gram 애플리케이션에서 profilepage js 는 유사한 기능을 구현하지만 더 많은 기능과 더 복잡한 ui를 가지고 있습니다 팔로워 수, 게시물 통계 및 더 강력한 이미지 처리와 같은 추가 필드를 포함합니다 back4gram 프로젝트 찾기 여기 전체 코드를 위한 소셜 네트워크 샘플 프로젝트 back4app으로 구축된 8단계 – 인증 시스템 테스트 및 보안 이제 인증 시스템을 구축했으니, 이를 제대로 테스트하고 보안하는 방법에 대해 논의해 보겠습니다 인증 흐름 테스트 인증 시스템을 테스트할 때, 다음의 각 흐름을 확인해야 합니다 사용자 등록 사용자가 유효한 자격 증명으로 계정을 생성할 수 있는지 테스트 입력 유효성 검사 잘못된 입력에 대해 적절한 오류가 나타나는지 확인 로그인 프로세스 사용자가 올바른 자격 증명으로 로그인할 수 있는지 확인 로그인 실패 잘못된 자격 증명에 대해 적절한 오류가 나타나는지 확인 비밀번호 재설정 비밀번호 재설정 흐름이 끝에서 끝까지 작동하는지 확인 세션 지속성 사용자가 페이지 방문 간에 로그인 상태를 유지하는지 확인 로그아웃 프로세스 사용자가 제대로 로그아웃할 수 있고 세션이 종료되는지 확인 피해야 할 일반적인 보안 취약점 인증 시스템을 구축할 때, 다음과 같은 일반적인 보안 문제를 인식해야 합니다 비밀번호 저장 비밀번호를 일반 텍스트로 저장하지 마십시오 back4app이 이를 자동으로 처리합니다 무차별 대입 공격 로그인 시도에 대한 비율 제한을 구현하십시오 back4app이 이 기능을 제공합니다 교차 사이트 스크립팅 (xss) 스크립트 주입을 방지하기 위해 사용자 입력을 정리하십시오 교차 사이트 요청 위조 (csrf) 요청의 진위를 확인하기 위해 적절한 토큰을 사용하십시오 불안전한 직접 객체 참조 url에 민감한 id나 참조를 노출하지 마십시오 back4app 보안 모범 사례 back4app은 활용해야 할 여러 보안 기능을 제공합니다 1 클래스 수준 권한 (clps) back4app 대시보드에서 객체를 읽고, 쓰고, 삭제할 수 있는 권한을 제어하기 위해 클래스 수준 권한을 설정할 수 있습니다 back4app 대시보드로 이동 데이터베이스 → 브라우저로 이동 사용자 클래스에 대한 "보안" 버튼을 클릭 권한을 적절하게 구성 \[이미지 back4app 클래스 수준 권한 화면에 사용자 클래스 보안 설정 표시] 사용자 클래스의 일반적인 설정은 다음과 같습니다 특정 필드(사용자 이름, 아바타)에 대해서만 공개 읽기 접근 허용 공개 쓰기 또는 삭제 접근 없음 인증된 사용자만 자신의 기록을 업데이트할 수 있음 2 접근 제어 목록 (acls) 개별 객체에 대해 acl을 사용하여 접근을 제어할 수 있습니다 // set an acl that only allows the current user to read and write this object const useracl = new parse acl(parse user current()); userobject setacl(useracl); await userobject save(); 이것은 객체를 생성한 사용자만 접근하거나 수정할 수 있도록 보장합니다 3 마스터 키 사용 back4app는 보안 검사를 우회하는 마스터 키를 제공합니다 클라이언트 측 코드에서 이를 노출하지 마십시오 // never do this in client side code parse cloud usemasterkey(); // this should only be used in cloud code 대신, 권한이 필요한 작업에는 클라우드 기능을 사용하세요 4 이메일 인증 사용자가 유효한 이메일 주소를 제공하도록 보장하기 위해 back4app 설정에서 이메일 인증을 활성화하세요 back4app 대시보드로 이동 앱 설정 → 이메일 설정으로 이동 이메일 어댑터 구성 이메일 인증 활성화 \[이미지 back4app 이메일 설정 구성 화면] 5 이중 인증 추가 보안을 위해 back4app 클라우드 기능을 사용하여 이중 인증을 구현할 수 있습니다 이는 사용자가 로그인할 때 두 번째 인증 형태(일반적으로 전화나 이메일로 전송된 코드)를 제공해야 함을 의미합니다 요금 제한 구현 무차별 공격으로부터 보호하기 위해 클라우드 기능을 사용하여 요금 제한을 구현할 수 있습니다 // cloud function to handle login with rate limiting parse cloud define("securelogin", async (request) => { const { username, password } = request params; // check for too many failed attempts const query = new parse query("loginattempt"); query equalto("username", username); query greaterthan("createdat", new date(date now() 15 60 1000)); // last 15 minutes const attempts = await query count(); if (attempts >= 5) { throw new error("too many login attempts please try again later "); } try { // attempt to log in const user = await parse user login(username, password); return { success true, user user tojson() }; } catch (error) { // record failed attempt const loginattempt = parse object extend("loginattempt"); const attempt = new loginattempt(); attempt set("username", username); await attempt save(null, { usemasterkey true }); throw error; } }); 결론 이 튜토리얼에서는 back4app을 사용하여 소셜 네트워크 애플리케이션을 위한 포괄적인 인증 시스템을 구축했습니다 사용자 등록, 로그인, 비밀번호 재설정 및 프로필 관리 기능을 구현했으며, 모두 back4app의 내장된 사용자 관리 기능을 통해 지원됩니다 배운 내용을 요약해 보겠습니다 back4app의 사용자 관리 시스템 back4app의 parse server가 내장된 사용자 인증을 제공하는 방법을 배웠습니다 parse user 클래스 사용자 등록 back4app의 데이터베이스에 새로운 사용자 계정을 생성하는 가입 양식을 구현했습니다 사용자 로그인 사용자를 인증하고 세션을 관리하는 로그인 시스템을 만들었습니다 비밀번호 재설정 복구 이메일을 전송하는 안전한 비밀번호 재설정 기능을 추가했습니다 세션 관리 사용자 세션을 유지하고 경로를 보호하는 방법을 배웠습니다 프로필 관리 사용자가 자신의 정보를 업데이트하고 프로필 사진을 업로드할 수 있는 프로필 페이지를 구축했습니다 보안 모범 사례 back4app의 보안 기능을 사용하여 인증 시스템을 보호하는 방법을 탐구했습니다 back4app을 사용하여 복잡한 백엔드 인프라를 구축하는 대신 훌륭한 사용자 경험을 만드는 데 집중할 수 있었습니다 back4app을 지원하는 parse server는 필요한 모든 인증 api를 제공하며, 사용자 데이터의 보안을 보장합니다 당신이 구축한 인증 시스템은 소셜 네트워크 애플리케이션의 기초를 형성합니다 이를 통해 이제 back4app을 백엔드 서비스로 사용하여 게시물, 댓글, 좋아요 및 직접 메시지와 같은 기능을 추가하여 애플리케이션을 확장할 수 있습니다 다음 단계 소셜 로그인 통합 back4app의 oauth 기능을 사용하여 google, facebook 또는 기타 제공업체로 로그인 추가 강화된 보안 추가 보안을 위해 이중 인증 구현 사용자 역할 다양한 유형의 사용자에 대한 역할 기반 접근 제어 설정 실시간 기능 back4app의 라이브 쿼리를 사용하여 실시간 메시징 및 알림 추가 back4gram 소셜 네트워크 애플리케이션의 전체 코드는 github 저장소 https //github com/templates back4app/back4gram 를 확인할 수 있습니다 back4app의 강력한 백엔드 서비스와 parse server 통합은 안전하고 확장 가능한 소셜 네트워크 애플리케이션을 구축하는 데 탁월한 선택입니다 내장된 사용자 관리 기능을 활용하여 최소한의 노력으로 강력한 인증 시스템을 만들 수 있으며, 이를 통해 애플리케이션을 돋보이게 하는 독특한 기능을 만드는 데 집중할 수 있습니다