我有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