Apollo 클라이언트 graphQL 및 Auth0: 완전한 구현

이 기사는 다양한 구현을 시도하고 Auth0 및 Apollo를 사용하기 위해 더 많은 레이어를 발견한 후 몇 달 동안 모였습니다. 일부 원칙은 다른 유사한 라이브러리에서도 잘 작동할 것이라고 확신합니다. 이 접근 방식은 여러 포럼과 GitHub 문제 및 기사에서 가져온 것이기 때문에 이 접근 방식을 인정하고 싶지 않습니다.

이 코드의 경우 비교적 새로운auth0-react 라이브러리를 사용하고 있지만 이 솔루션은 auth0-spa SDK와 함께 사용할 수 있습니다. 튜토리얼을 기반으로 apollo client/auth0/react와 함께 인증된 graphQL 서버를 사용하려고 할 때 결코 해결되지 않은 것처럼 보이는 문제 중 하나는 토큰을 얻는 깨끗한 방법이었고 토큰이 만료된 경우 토큰을 원활하게 업데이트하고 다시 시도했습니다. 쿼리/돌연변이.

대부분의 솔루션이 로컬 저장소에서 토큰을 가져오는 것처럼 보였지만authentication 만료된 토큰이 있는 경우 제공되는 유일한 솔루션은 만료된 토큰을 삭제하고 사용자를 로그아웃하는 것 같았습니다. 초기 중단은 auth0 forummattwilson1024에서 왔습니다.
AuthorizedApolloProvider.tsx
import { ApolloClient, ApolloProvider, createHttpLink, InMemoryCache } from '@apollo/client';
import { setContext } from '@apollo/link-context';
import React from 'react';

import { useAuth0 } from '../react-auth0-spa';

const AuthorizedApolloProvider = ({ children }) => {
  const { getTokenSilently } = useAuth0();

  const httpLink = createHttpLink({
    uri: 'http://localhost:4000/graphql', // your URI here...
  });

  const authLink = setContext(async () => {
    const token = await getTokenSilently();
    return {
      headers: {
        Authorization: `Bearer ${token}`
      }
    };
  });

  const apolloClient = new ApolloClient({
    link: authLink.concat(httpLink),
    cache: new InMemoryCache(),
    connectToDevTools: true
  });

  return (
    <ApolloProvider client={apolloClient}>
      {children}
    </ApolloProvider>
  );
};

export default AuthorizedApolloProvider;


Apollo 공급자 주위에 React 구성 요소를 생성하면 모든 React Hooks와 기능을 사용할 수 있습니다. 따라서 Auth0 후크에서 토큰을 가져오는 것은 항상 작동하는 토큰이며 저장된 토큰이 만료된 경우 Apollo가 아니라 토큰 새로 고침을 담당하는 Auth0 라이브러리가 됩니다.

이제 apollo 문서를 기반으로 middleware link 헤더를 생성하여 헤더를 추가하는 올바른 방법을 기반으로 합니다. 그러나 함수가 비동기로 작동하는 것은 아니므로 setContext 링크를 사용하도록 전환해야 했습니다. https://www.apollographql.com/docs/link/links/context/

이것의 문제는 다른 헤더 속성을 전달하는 경우 해당 속성이 통과하지 못하게 하고 apollo setContext 문서에서 호출에서 헤더를 가져오는 방법에 대해 언급하지 않는다는 것입니다https://github.com/apollographql/apollo-client/issues/4990. 헤더.

각 쿼리에서 전달된 추가 헤더를 허용하는 AuthorizedApolloProvider의 최종 구현은 다른 유용한 링크도 구현했습니다. logRocket을 사용하는 경우의 작은 수정:

import { ApolloClient } from 'apollo-client';
import { ApolloLink } from 'apollo-link';
import { ApolloProvider } from 'react-apollo';
import { BatchHttpLink } from 'apollo-link-batch-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { onError } from 'apollo-link-error';
import { RetryLink } from 'apollo-link-retry';
import { useAuth0 } from '@auth0/auth0-react';
import LogRocket from 'logrocket';
import React from 'react';
import { setContext } from 'apollo-link-context';

// IF you want to enable/disable dev tools in different enviroments
const devTools = localStorage.getItem('apolloDevTools') || false;

const AuthorizedApolloProvider = ({ children }) => {
    const { getAccessTokenSilently } = useAuth0();
    const authMiddleware = setContext(async (_, { headers, ...context }) => {
        const token = await getAccessTokenSilently();
//Optional if the ti
        if (typeof Storage !== 'undefined') {
            localStorage.setItem('token', token);
        }

        console.log('Network ID:', activeNetworkID);
        return {
            headers: {
                ...headers,
                ...(token ? { Authorization: `Bearer ${token}` } : {}),
            },
            ...context,
        };
    });

    /**
     * Adding fix to improve logRocket recording
     * https://docs.logrocket.com/docs/troubleshooting-sessions#apollo-client
     */

    const fetcher = (...args) => {
        return window.fetch(...args);
    };

    const client = new ApolloClient({
        link: ApolloLink.from([
            onError(({ graphQLErrors, networkError }) => {
                if (graphQLErrors) {
                    LogRocket.captureException(graphQLErrors);
                    graphQLErrors.forEach(({ message, locations, path }) =>
                        console.error(
                            `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
                        )
                    );
                }
                if (networkError) {
                    // localStorage.removeItem('token');
                    LogRocket.captureException(networkError);
                    console.error(`[Network error]:`, networkError);
                }
            }),
            authMiddleware,
            new RetryLink(),
            new BatchHttpLink({
                uri: `${getConfig().apiUrl}`,
                fetch: fetcher,
            }),
        ]),
        cache: new InMemoryCache(),
        connectToDevTools: devTools,
    });

    return <ApolloProvider client={client}>{children}</ApolloProvider>;
};

export default AuthorizedApolloProvider;

좋은 웹페이지 즐겨찾기