"일꾼이 일을 잘하려면 먼저 도구를 갈고 닦아야 한다." - 공자, 『논어』.
첫 장 > 프로그램 작성 > Nanostore 및 Context API를 사용하여 React 앱에서 인증 처리

Nanostore 및 Context API를 사용하여 React 앱에서 인증 처리

2024-08-20에 게시됨
검색:297

HANDLING AUTH IN REACT APPS USING NANOSTORES AND CONTEXT API

ReactJ를 사용하여 풀 스택 웹 앱을 구축하는 초보 시절에 저는 프런트엔드에서 인증을 처리하는 방법에 대해 혼란스러워했습니다. 즉, 백엔드에서 액세스 토큰을 받은 후 다음에 무엇을 해야 합니까? 로그인 상태를 어떻게 유지하나요?

대부분의 초보자는 "아, 그냥 토큰을 상태에 저장하세요"라고 가정합니다. 그러나 나는 이것이 최고의 솔루션이 아니었고 전혀 솔루션이 아니라는 것을 빨리 알게 되었습니다. 대부분의 숙련된 ReactJs 개발자가 알고 있듯이 상태는 페이지를 새로 고칠 때마다 지워지기 때문에 일시적이므로 우리는 확실히 할 수 있습니다. 새로 고칠 때마다 사용자가 로그인할 필요가 없습니다.

반응으로 풀 스택 앱을 구축하고 경험이 풍부한 개발자의 인증 접근 방식을 연구하고 다른 두 애플리케이션에서 프로세스를 복제하는 데 약간의 경험을 얻었으므로 가이드를 제공하고 싶습니다. 내가 현재 어떻게 처리하고 있는지. 어떤 사람들은 그것이 최선의 방법이라고 생각하지 않을 수도 있지만 나는 지금까지 그것을 내 방식으로 채택했고 다른 개발자들이 사용하는 다른 방법을 배우는 데 열려 있습니다.

1단계

인증 프로세스를 시작하기 위해 이메일과 비밀번호(기본 이메일 및 비밀번호 인증을 사용한다고 가정)를 백엔드에 제출했습니다. 이 문서에서는 인증을 프런트엔드에서만 처리하는 방법에 대해 다루기 때문에 백엔드에서 인증을 처리하는 방법에 대해서는 언급하지 않겠습니다. HTTP 응답에서 토큰을 받은 부분으로 건너뛰겠습니다. 다음은 이메일과 비밀번호를 서버에 제출하고 응답으로 토큰과 사용자 정보를 받는 간단한 로그인 양식 구성 요소의 코드 예제입니다. 이제 단순화를 위해 내 양식 값은 상태로 관리되므로 프로덕션 앱에는 formik과 같은 강력한 라이브러리를 사용하는 것이 훨씬 더 나을 것입니다.

import axios from 'axios'
import { useState } from "react"

export default function LoginForm() {
    const [email, setEmail] = useState("")
    const [password, setPassword] = useState("")

    const handleSubmit = async() => {
        try {
            const response = await axios.post("/api/auth/login", { email, password })
            if (response?.status !== 200) {
                throw new Error("Failed login")
            }
            const token = response?.data?.token
            const userInfo = response?.data?.userInfo
        } catch (error) {
            throw error
        }
    }

    return(
        
setEmail(e.target.value)}/> setPassword(e.target.value)}/>
) }

2단계

전체 애플리케이션을 래핑하거나 인증 컨텍스트 공급자의 인증 상태에 액세스해야 하는 부분만 래핑합니다. 이는 일반적으로 루트 App.jsx 파일에서 수행됩니다. context API가 무엇인지 모른다면 Reactjs 문서를 확인해 보세요. 아래 예에서는 생성된 AuthContext 공급자 구성 요소를 보여줍니다. 그런 다음 App.jsx로 가져오고 App 구성 요소에 반환된 RouterProvider를 래핑하는 데 사용되므로 애플리케이션의 어디에서나 인증 상태에 액세스할 수 있습니다.

import { createContext } from "react";

export const AuthContext = createContext(null)

export default function AuthProvider({children}) {

    return(
        
            {children}
        
    )
}
import React from "react";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import AuthProvider from "./AuthContext";

const router = createBrowserRouter([
    // your routes here
])

function App() {
    return(
        
    )
}

export default App

3단계

인증 컨텍스트에서는 "isLoggedIn" 및 "authenticatedUser"라는 두 가지 상태 변수를 초기화해야 합니다. 첫 번째 상태는 처음에 'false'로 설정되고 로그인이 확인되면 'true'로 업데이트되는 부울 유형입니다. 두 번째 상태 변수는 이름, 이메일 등과 같은 로그인된 사용자 정보를 저장하는 데 사용됩니다. 이러한 상태 변수는 조건부 렌더링을 위해 애플리케이션 전체에서 액세스할 수 있도록 컨텍스트 구성 요소에 반환된 공급자 값에 포함되어야 합니다. .

import { createContext, useState } from "react";

export const AuthContext = createContext(null)

export default function AuthProvider({children}) {
    const [isLoggedIn, setIsLoggedIn] = useState(false)
    const [authenticatedUser, setAuthenticatedUser] = useState(null)

    const values = {
        isLoggedIn,
        authenticatedUser,
        setAuthenticatedUser
    }

    return(
        
            {children}
        
    )
}

4단계

Nanostores는 Javascript 앱의 상태를 관리하기 위한 패키지입니다. 패키지는 별도의 파일에서 간단히 초기화하고 상태를 사용하거나 업데이트하려는 구성 요소로 가져오는 방식으로 여러 구성 요소의 상태 값을 관리하기 위한 간단한 API를 제공합니다. 그러나 1단계의 HTTP 응답에서 수신된 인증 토큰을 저장하기 위해 nanostores/persist를 사용하게 됩니다. 이 패키지는 상태를 localStorage에 저장하여 상태를 유지하므로 페이지를 새로 고칠 때 지워지지 않습니다. @nanostores/react는 nanostore에 대한 특정 반응 통합으로, nanostore 상태에서 값을 추출하기 위한 useStore 후크를 사용할 수 있게 합니다.

이제 다음과 같이 진행할 수 있습니다.

  • nanostores, @nanostores/percious 및 @nanostores/react 패키지를 설치합니다.

  • user.atom.js라는 별도의 파일 또는 원하는 이름으로 선택한 파일에서 nanostores/pertant를 사용하여 'authToken' 저장소와 '사용자' 저장소를 초기화합니다.

  • 이를 로그인 양식 구성 요소 파일로 가져오고 로그인 응답에서 받은 토큰 및 사용자 데이터로 상태를 업데이트합니다.

npm i nanostores @nanostores/persistent @nanostores/react
import { persistentMap } from '@nanostores/persistent'

export const authToken = persistentMap('token', null)

export const user = persistentMap('user', null)
import { authToken, user } from './user.atom'

 const handleSubmit = async() => {
        try {
            const response = await axios.post("/api/auth/login", { email, password })
            if (response?.status !== 200) {
                throw new Error("Failed login")
            }
            const token = response?.data?.token
            const userInfo = response?.data?.userInfo

            authToken.set(token)
            user.set(userInfo)
        } catch (error) {
            throw error
        }
    }

5단계

이제 앱을 래핑하는 인증 컨텍스트에서 토큰과 사용자 상태가 계속 업데이트되고 전체 앱에서 사용할 수 있는지 확인해야 합니다. 이를 달성하려면 다음을 수행해야 합니다.

  • 'authToken' 및 '사용자' 스토어를 가져옵니다.

  • useEffect 후크를 후크 내부에서 초기화하고 토큰이 'authToken' 저장소에 있는지 확인하는 'checkLogin()' 함수를 생성합니다. 존재하는 경우 토큰이 있는지 확인하는 함수를 실행합니다. 만료되었습니다. 확인 결과에 따라 사용자를 로그인 페이지로 리디렉션하여 인증을 받거나… 'isLoggedIn' 상태를 true로 설정합니다. 이제 로그인 상태가 더 자주 추적되도록 하기 위해 현재 경로가 변경될 때마다 이 후크가 실행되도록 설정할 수 있습니다. 이렇게 하면 앱과 상호작용하는 동안 토큰이 만료되면 사용자가 쫓겨나거나 로그인 페이지로 리디렉션될 수 있습니다. .

  • 앱이 로드되거나 새로 고쳐질 때마다 authToken 저장소의 토큰을 사용하여 백엔드에서 사용자 정보를 가져오는 기능이 포함된 또 다른 useEffect 후크를 초기화합니다. 성공적인 응답을 받으면 'isLoggedIn' 상태를 true로 설정하고 'authenticatedUser' 상태와 'user' 스토어를 응답에서 받은 사용자 정보로 업데이트하세요.

다음은 업데이트된 AuthProvider 구성 요소 파일입니다.

import { createContext, useState } from "react";
import { authToken, user } from './user.atom';
import { useStore } from "@nanostores/react";
import { useNavigate, useLocation } from "react-router-dom";
import axios from "axios";

export const AuthContext = createContext(null)

export default function AuthProvider({children}) {
    const [isLoggedIn, setIsLoggedIn] = useState(false)
    const [authenticatedUser, setAuthenticatedUser] = useState(null)
    const token = useStore(authToken)
    const navigate = useNavigate()
    const { pathname } = useLocation()

    function isTokenExpired() {
        // verify token expiration and return true or false
    }

    // Hook to check if user is logged in 
    useEffect(() => {
        async function checkLogin () {
            if (token) {

              const expiredToken = isTokenExpired(token);

              if (expiredToken) {
                // clear out expired token and user from store and navigate to login page
                authToken.set(null)
                user.set(null)
                setIsLoggedIn(false);
                navigate("/login");
                return;
              }
            }
        };

        checkLogin()
    }, [pathname])

    // Hook to fetch current user info and update state
    useEffect(() => {
        async function fetchUser() {
            const response = await axios.get("/api/auth/user", {
                headers: {
                    'Authorization': `Bearer ${token}`
                }
            })

            if(response?.status !== 200) {
                throw new Error("Failed to fetch user data")
            }

            setAuthenticatedUser(response?.data)
            setIsLoggedIn(true)
        }

        fetchUser()
    }, [])

    const values = {
        isLoggedIn,
        authenticatedUser,
        setAuthenticatedUser
    }

    return(
        
            {children}
        
    )
}

결론

이제 5단계에서 생성된 두 개의 useEffect 후크가 전체 앱의 인증 상태를 관리하는 역할을 담당합니다. 새로 고침을 수행할 때마다 로컬 저장소에서 토큰을 확인하고 백엔드에서 직접 최신 사용자 데이터를 검색하고 'isLoggedIn' 및 'authenticatedUser' 상태를 업데이트하기 위해 실행됩니다. React에서 'AuthContext' 및 'useContext' 후크를 가져오고 구성 요소 내에서 이를 호출하여 값에 액세스하고 일부 조건부 렌더링에 사용함으로써 모든 구성 요소 내에서 상태를 사용할 수 있습니다.

import { useContext } from "react";
import { AuthContext } from "./AuthContext";

export default function MyLoggedInComponent() {

    const { isLoggedIn, authenticatedUser } = useContext(AuthContext)

    return(
        
        {
            isLoggedIn ? 
            

Welcome {authenticatedUser?.name}

: } > ) }

로그아웃 시 'authToken' 및 'user' 저장소를 null로 설정하여 지워야 한다는 점을 기억하세요. 또한 'isLoggedIn'을 false로 설정하고 'authenticatedUser'를 null로 설정해야 합니다.

읽어주셔서 감사합니다!

릴리스 선언문 이 기사는 https://dev.to/ikemcodedit/handling-auth-in-react-apps-using-nanostores-and-context-api-35kg?1에서 복제됩니다. 침해가 있는 경우, Study_golang@163으로 문의하시기 바랍니다. .com에서 삭제하세요
최신 튜토리얼 더>

부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.

Copyright© 2022 湘ICP备2022001581号-3