React Context 和 Apollo Client Link 之间的通信

Moo*_*ing 8 jwt reactjs apollo-client

我正在使用 React 和 Apollo Client 开发一个单页 Web 应用程序,我想知道如何在 Apollo 客户端链接和 React 上下文之间正确传达身份验证状态。

在客户端中,我编写了一个 AuthProvider 上下文来提供当前用户信息,以便我可以在组件树中的任何位置执行

const authState = useAuthState()
const dispatch = useAuthDispatch()
Run Code Online (Sandbox Code Playgroud)

从而根据需要查询和更新身份验证信息。例如,我使用它来编写一个PrivateRoute组件,如果未通过身份验证,则重定向查看者:

const PrivateRoute: FunctionComponent<RouteProps> = ({ children, ...rest }) => {
    const authState = useAuthState()

    return (
        <Route
            {...rest}
            render={({ location }) =>
                authState.user ? (
                    children
                ) : (
                    <Redirect
                        to={{
                            pathname: "/login",
                            state: { from: location }
                        }}
                    />
                )
            }
        />
    )
}
Run Code Online (Sandbox Code Playgroud)

这一切都很好。当将此与我选择的身份验证形式(JWT)结合起来时,我的问题出现了。我将访问令牌存储在 中,authState并且刷新令牌在登录时由后端设置为 httpOnly cookie。

但我必须Authorization: Bearer在每个请求上将访问令牌作为标头发送,我想使用 Apollo Link 来完成此操作,如下所示:

const authLink = setContext(async (_, { headers }) => {
    const token = getTokenFromAuthStateSomehow()

    return {
        headers: {
            ...headers,
            authorization: token ? `Bearer ${token}` : ""
        }
    }
})
Run Code Online (Sandbox Code Playgroud)

但这是在 Apollo Link 内,我当然无法直接访问 React Context。getTokenFromAuthStateSomehow()是个函数我不知道怎么写。

那么下一个问题是当该请求因访问令牌已过期而失败时会发生什么。我想使用 ApolloonError捕获来自 API 的 401 错误,并通过获取刷新的令牌重试请求:

const retryLink = onError(({ networkError }) => {
    if (networkError) {
        const newToken = getRefreshedToken()

        if (newToken) {
            retryRequest()
            setTokenInAuthStateSomehow(newToken)
        }
    }
})
Run Code Online (Sandbox Code Playgroud)

但是我们遇到了同样的问题 - 现在我需要将新令牌发送回authState即发送到 React Context:setTokenInAuthStateSomehow()是一个我也不知道如何编写的函数。

因此,最重要的问题是:如何在 Apollo Link 和 React Context 之间进行通信?我是否必须以某种方式设置一些侦听器或事件?我希望得到任何信息或推动正确的方向。