【问题标题】:how to add auth0 access token to react-apollo如何将 auth0 访问令牌添加到 react-apollo
【发布时间】:2021-04-29 05:57:33
【问题描述】:

我正在尝试在 react js 中向 apollo 客户端添加授权令牌以让用户登录...

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import { ThemeProvider } from 'react-jss';
import Theme from 'resources/theme';
import Routes from 'routes';
import './index.css';
import * as serviceWorker from './serviceWorker';
import { Auth0Provider } from "@auth0/auth0-react";
import 'bootstrap/dist/css/bootstrap.min.css';
import ReactNotification from 'react-notifications-component'
import './components/orders/fonts/NotoSansJP-Regular.otf'
import 'react-notifications-component/dist/theme.css'
import { ApolloProvider , ApolloClient, InMemoryCache } from '@apollo/client';
import { useAuth0 } from "@auth0/auth0-react";


const client = new ApolloClient({
uri: process.env.REACT_APP_API_BACK ,
headers: {
  Authorization: `Bearer ${accessToken}` // doesn’t work 
 },
  cache: new InMemoryCache()
});


ReactDOM.render(
     <Auth0Provider
    domain= {process.env.REACT_APP_AUTH0_DOMAIN }
  clientId= {process.env.REACT_APP_AUTH0_CLIENT_ID}
   redirectUri={window.location.origin}
   audience={process.env.REACT_APP_AUTH0_AUDIENCE}
   scope="warehouse"
   
  >
    <ApolloProvider client={client}> 
    <ThemeProvider theme={Theme}>
        <Router>
        <ReactNotification />
            <Routes />
        </Router>
    </ThemeProvider>,
    </ApolloProvider>
      </Auth0Provider>,
    document.getElementById('root')
);

serviceWorker.unregister();

获取我需要导入的令牌:

import { useAuth0 } from "@auth0/auth0-react";

添加这行:

const {  getAccessTokenSilently } = useAuth0();

但这不能在 index.js 我认为

获取令牌:

 const accessToken = await getAccessTokenSilently

这是我在文档和谷歌搜索中找到的,但我认为在我的情况下无法完成,大多数教程都展示了如何在个人资料页面中获取用户数据(包括令牌),但这不是我想要的.

我想将它传递给 index.js 中的 client

【问题讨论】:

    标签: reactjs apollo auth0 apollo-client react-apollo


    【解决方案1】:

    您需要为

    创建专用组件
    function useToken() {
      const {  getAccessTokenSilently } = useAuth0();
      const [token, setToken] = useState(null);
    
      useEffect(() => { getAccessTokenSilently().then(setToken) }, [])
    
      return token;
    }
    
    function MyApolloProvider({ children }) {
      const token = useToken();
    
      // useRef instead of useMemo to make sure client is not re-created randomly
      const clientRef = useRef(null);
    
      if (token && !clientRef.current) {
        // This code should only be executed once.
        clientRef.current = new ApolloClient(/**/)
      }
    
      if (!clientRef.current) {
        // Now we have to wait until client is initialized with token, so you might want to add some spinner
        return null;
      }
    
      return <ApolloClient client={clientRef.current} >{children}</ApolloClient> 
    }
    

    然后你在你的 ReactDOM.render 中使用它而不是原来的 ApolloProvider。

    如果令牌发生变化,那么事情就会变得更加困难。 https://www.apollographql.com/docs/react/networking/authentication/#header

    你仍然使用类似的方法:

    function useToken() { /* should return actual token and update it if changed */ }
    
    function MyApolloProvider({ children }) {
      const token = useToken();
      const tokenRef = useRef(token);
      const clientRef = useRef(null);
    
      tokenRef.current = token; // make sure that tokenRef always has up to date token
    
      if (!clientRef.current) {
        // This function is called on each request individually and it takes token from ref
        const authLink = setContext((_, { headers }) => {
          // similar to documentation example, but you read token from ref
          const token = tokenRef.current;
    
          return {
            headers: {
              ...headers,
              authorization: `Bearer ${token}`,
            }
          }
        });
    
        clientRef.current = new ApolloClient(
          link: authLink.concat(httpLink),
          // ...
        )
    
      }
    }
    

    index.js 中的用法,无论是第一种还是第二种情况:

    ReactDOM.render(
      <Auth0Provider /* options */>
        <MyApolloProvider>
          {/* ... */}
        </MyApolloProvider>
      </Auth0Provider>,
      document.getElementById("root")
    );
    

    这里的主要内容是MyApolloProvider 应该在Auth0Provider 内才能访问令牌。

    【讨论】:

    • 第二个例子你能补一下代码吗?以及如何在索引中使用它。 js ?
    • 我尝试了相同的方法,但使用不同的代码并且出现了交叉问题,我认为使用此代码我会遇到同样的问题
    【解决方案2】:

    这就是我最终做的:

    import {
      ApolloProvider,
      ApolloClient,
      InMemoryCache,
      HttpLink,
    } from '@apollo/client';
    import { setContext } from '@apollo/link-context';
    import { useAuth0 } from '@auth0/auth0-react';
    
    const ApolloProviderWithAuth0 = ({ children }) => {
      const { getAccessTokenSilently } = useAuth0();
    
      const httpLink = new HttpLink({
        uri: process.env.REACT_APP_GRAPHQL_URI,
      });
    
      const authLink = setContext(async (_, { headers, ...rest }) => {
        let token;
        try {
          token = await getAccessTokenSilently();
        } catch (error) {
          console.log(error);
        }
    
        if (!token) return { headers, ...rest };
    
        return {
          ...rest,
          headers: {
            ...headers,
            authorization: `Bearer ${token}`,
          },
        };
      });
    
      const client = React.useRef();
    
      if (!client.current) {
        client.current = new ApolloClient({
          link: authLink.concat(httpLink),
          cache: new InMemoryCache(),
        });
      }
    
      return (
        <ApolloProvider client={client.current}>
          {children}
        </ApolloProvider>
      );
    };
    
    export { ApolloProviderWithAuth0 };
    

    然后在您的 App 组件中将其用作 Provider。

    【讨论】:

      猜你喜欢
      • 2020-12-17
      • 2017-12-29
      • 2019-12-18
      • 2019-07-20
      • 2023-03-21
      • 2021-04-13
      • 1970-01-01
      • 2018-01-13
      • 2017-01-16
      相关资源
      最近更新 更多