如何在使用 Apollo 和 React Native 的每个 graphql 请求之前实现自动 jwt 令牌刷新?
How to implement auto jwt token refresh before every graphql request with Apollo and React Native?
我想在对 GraphQL 的每个请求之前使用 React Native 中的 Apollo 中间件实现自动刷新 jwt 令牌 应用程序。每次用户登录后,他都会获得两个令牌:访问和刷新。访问令牌是用于授权的 30-60 分钟的短令牌 header。刷新令牌是 60 天的长令牌,用于确认刷新令牌 graphql 突变。
我的流量:
- 用户登录并获得 2 个令牌 -> 使用 Appollo setContext.
将访问令牌授权 header
- 用户向 GraphQL 发出请求 -> 检查客户端 accessToken 的过期时间:
-> 如果没有过期 -> 确认请求
-> 如果它已过期 -> 调用 GraphQL refreshToken 突变 -> 获取新令牌 -> 确认请求。
为了在客户端保留令牌,我使用 KeyChain 存储。你能告诉我我是否也应该使用 Apollo 缓存来保存令牌?我应该为令牌写 Apollo 状态吗?我如何实施我的流程?
GraphQL 突变
mutation UpdateTokens($refreshToken: String!, $refreshTokenId: String!)
{
updateTokens(refreshToken: $refreshToken, refreshTokenId: $refreshTokenId) {
user {
name
phone
}
accessToken
refreshToken
}
}
App.js
import React from 'react'
import { ApolloClient } from 'apollo-client'
import { ApolloLink } from 'apollo-link'
import { ApolloProvider } from 'react-apollo'
import { ApolloProvider as ApolloHooksProvider } from 'react-apollo-hooks'
import { createHttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { setContext } from 'apollo-link-context'
import * as Keychain from 'react-native-keychain'
import AppNavigator from './AppNavigator'
const httpLink = createHttpLink({
uri: 'http://localhost:4000'
})
const cache = new InMemoryCache()
const authLink = setContext(async (req, { headers, ...context }) => {
const tokens = await Keychain.getGenericPassword()
const accessToken = tokens.username
return {
headers: {
...headers,
authorization: accessToken ? `Bearer ${accessToken}` : ''
},
...context
}
})
const client = new ApolloClient({
link: ApolloLink.from([authLink, httpLink]),
cache,
connectToDevTools: true
})
const App = () => {
return (
<ApolloProvider client={client}>
<ApolloHooksProvider client={client}>
<AppNavigator />
</ApolloHooksProvider>
</ApolloProvider>
)
}
export default App
老实说,我认为您走在正确的道路上——当我阅读您所需的功能时,我想到了 apollo-link-context
并且很高兴看到您采用了这种方法。我们最近不得不在 react-native 应用程序中实现类似的功能,这需要将自定义 headers 与 authentication-related 数据相关联。要检索此数据,我们需要发出异步请求,尽管我们的请求是通过网络连接到 third-party 服务。就像您一样,我们在 setContext
中从客户那里完成了这一切。这很好用。
我认为您不需要手动或以其他方式使用令牌更新 Apollo 缓存,至少有几个原因。首先,考虑到您所存储内容的 quasi-sensitive 性质,最好采用更安全的存储解决方案,在本例中可能是钥匙串。此外,为应用程序中的令牌提供单一真实来源可以使事情保持清洁。
假设您不想将此数据写入缓存,我会 double-check Apollo 客户端不会自动这样做。例如,如果您之前出于某种原因查询了您的令牌数据,Apollo 可能会在收到突变负载后自动更新您的缓存。只是需要注意的事情。
我想在对 GraphQL 的每个请求之前使用 React Native 中的 Apollo 中间件实现自动刷新 jwt 令牌 应用程序。每次用户登录后,他都会获得两个令牌:访问和刷新。访问令牌是用于授权的 30-60 分钟的短令牌 header。刷新令牌是 60 天的长令牌,用于确认刷新令牌 graphql 突变。 我的流量:
- 用户登录并获得 2 个令牌 -> 使用 Appollo setContext. 将访问令牌授权 header
- 用户向 GraphQL 发出请求 -> 检查客户端 accessToken 的过期时间: -> 如果没有过期 -> 确认请求 -> 如果它已过期 -> 调用 GraphQL refreshToken 突变 -> 获取新令牌 -> 确认请求。 为了在客户端保留令牌,我使用 KeyChain 存储。你能告诉我我是否也应该使用 Apollo 缓存来保存令牌?我应该为令牌写 Apollo 状态吗?我如何实施我的流程?
GraphQL 突变
mutation UpdateTokens($refreshToken: String!, $refreshTokenId: String!)
{
updateTokens(refreshToken: $refreshToken, refreshTokenId: $refreshTokenId) {
user {
name
phone
}
accessToken
refreshToken
}
}
App.js
import React from 'react'
import { ApolloClient } from 'apollo-client'
import { ApolloLink } from 'apollo-link'
import { ApolloProvider } from 'react-apollo'
import { ApolloProvider as ApolloHooksProvider } from 'react-apollo-hooks'
import { createHttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { setContext } from 'apollo-link-context'
import * as Keychain from 'react-native-keychain'
import AppNavigator from './AppNavigator'
const httpLink = createHttpLink({
uri: 'http://localhost:4000'
})
const cache = new InMemoryCache()
const authLink = setContext(async (req, { headers, ...context }) => {
const tokens = await Keychain.getGenericPassword()
const accessToken = tokens.username
return {
headers: {
...headers,
authorization: accessToken ? `Bearer ${accessToken}` : ''
},
...context
}
})
const client = new ApolloClient({
link: ApolloLink.from([authLink, httpLink]),
cache,
connectToDevTools: true
})
const App = () => {
return (
<ApolloProvider client={client}>
<ApolloHooksProvider client={client}>
<AppNavigator />
</ApolloHooksProvider>
</ApolloProvider>
)
}
export default App
老实说,我认为您走在正确的道路上——当我阅读您所需的功能时,我想到了 apollo-link-context
并且很高兴看到您采用了这种方法。我们最近不得不在 react-native 应用程序中实现类似的功能,这需要将自定义 headers 与 authentication-related 数据相关联。要检索此数据,我们需要发出异步请求,尽管我们的请求是通过网络连接到 third-party 服务。就像您一样,我们在 setContext
中从客户那里完成了这一切。这很好用。
我认为您不需要手动或以其他方式使用令牌更新 Apollo 缓存,至少有几个原因。首先,考虑到您所存储内容的 quasi-sensitive 性质,最好采用更安全的存储解决方案,在本例中可能是钥匙串。此外,为应用程序中的令牌提供单一真实来源可以使事情保持清洁。
假设您不想将此数据写入缓存,我会 double-check Apollo 客户端不会自动这样做。例如,如果您之前出于某种原因查询了您的令牌数据,Apollo 可能会在收到突变负载后自动更新您的缓存。只是需要注意的事情。