异步Apollo setContext保存旧令牌而不是新令牌

时间:2019-07-23 13:51:14

标签: react-native graphql apollo prisma

我有react-native / graphql / apollo应用程序,使用setContext作为HTTP标头从服务器保存令牌。令牌保存在客户端的钥匙串存储中。要使用async / await检索令牌的唯一可能方式。第一个问题setContext在用户登录时不保存令牌,因为令牌仅在获得服务器授权后才获得,但是setContext在开始时进行了初始化。第二个是当我调用时:updateTokens => setContext保存旧的过期令牌=>我从服务器获取带有新令牌的新凭据。这意味着setContext而不是新的令牌将写以前的旧令牌。有人可以帮我了解发生了什么事

App.js

import React from 'react'
import { ApolloProvider } from 'react-apollo'
import { ApolloProvider as ApolloHooksProvider } from 'react-apollo-hooks'
import { ApolloClient } from 'apollo-client'
import { ApolloLink } from 'apollo-link'
import { createHttpLink } from 'apollo-link-http'
import { setContext } from 'apollo-link-context'
import { InMemoryCache } from 'apollo-cache-inmemory'
import * as Keychain from 'react-native-keychain'
import AppNavigator from './AppNavigator'

const httpLink = createHttpLink({
  uri: 'http://localhost:4000'
})

const authLink = setContext(async (req, { headers, ...context }) => {
  console.log('context', context)
  const tokens = await Keychain.getGenericPassword()
  console.log('tokensSetContext', tokens)
  const accessToken = tokens.username
  console.log('accessTokenSetContext', accessToken)
  return {
    headers: {
      ...headers,
      authorization: accessToken ? `Bearer ${accessToken}` : ''
    },
    ...context
  }
})

const client = new ApolloClient({
  link: ApolloLink.from([authLink, httpLink]),
  cache: new InMemoryCache(),
  connectToDevTools: true
})

const App = () => {
  console.log('authLink', authLink)
  return (
    <ApolloProvider client={client}>
      <ApolloHooksProvider client={client}>
        <AppNavigator />
      </ApolloHooksProvider>
    </ApolloProvider>
  )
}

export default App

updateTokens:

import React from 'react'
import { View, Button, Text } from 'react-native'
import { useMutation } from 'react-apollo-hooks'
import * as Keychain from 'react-native-keychain'
import jwtDecode from 'jwt-decode'
import { ScreenHeader } from '../../components'
import { UPDATE_TOKENS, SIGN_OUT } from '../../graphql/mutations'

const ChatFavoritesScreen = ({ navigation }) => {
  const update_tokens = useMutation(UPDATE_TOKENS)

  const updateTokens = (refreshToken, refreshTokenId) => {
    update_tokens({
      variables: { refreshToken, refreshTokenId },
      update: async (cache, { data }) => {
        const newAccessToken = data.updateTokens.accessToken
        const newRefreshToken = data.updateTokens.refreshToken
        const user = data.updateTokens.user
        await Keychain.setGenericPassword(newAccessToken, newRefreshToken)
      }
    }).then(() => console.log('We have new credentials'))
  }

  const getCredentials = async () => {
    try {
      const tokens = await Keychain.getGenericPassword()
      const keychainAccessToken = tokens.username
      const keychainRefreshToken = tokens.password
      const currentTime = Date.now() / 1000
      const decodeAccessToken = jwtDecode(keychainAccessToken)
      const keychainRefreshTokenId = decodeAccessToken.refreshTokenId
      if (decodeAccessToken.exp > currentTime) {
        console.log('Credentials is still valid')
      } else if (decodeAccessToken.exp < currentTime) {
        console.log('Go to Update!')
        updateTokens(keychainRefreshToken, keychainRefreshTokenId)
      }
    } catch (err) {
      throw new Error('Invalid credentials')
    }
  }

  return (
    <View style={{ flex: 1 }}>
      <ScreenHeader
        header="Chat"
        leftIconName="ios-arrow-back"
        rightIconName="ios-add"
        onLeftIconPress={() => navigation.goBack()}
        onRightIconPress={() => console.log('Right icon pressed')}
      />
      <Text>Home Screen</Text>
      <Button title="updateTokens" onPress={getCredentials} />
      <Button title="getCredentials" onPress={checkCredentials} />
    </View>
  )
}
export default ChatFavoritesScreen

0 个答案:

没有答案