Dav*_*tti 5 firebase apollo reactjs firebase-authentication apollo-link
目前,当我使用 firebase 对用户进行身份验证时,我将他们的身份验证令牌存储在localStorage稍后用于连接到我的后端,如下所示:
const httpLink = new HttpLink({uri: 'http://localhost:9000/graphql'})
const authMiddleware = new ApolloLink((operation, forward) => {
// add the authorization token to the headers
const token = localStorage.getItem(AUTH_TOKEN) || null
operation.setContext({
headers: {
authorization: token ? `Bearer ${token}` : ''
}
})
return forward(operation)
})
const authAfterware = onError(({networkError}) => {
if (networkError.statusCode === 401) AuthService.signout()
})
function createApolloClient() {
return new ApolloClient({
cache: new InMemoryCache(),
link: authMiddleware.concat(authAfterware).concat(httpLink)
})
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,一旦令牌过期,我就无法刷新它。所以我尝试使用以下内容为 apollo 设置授权令牌:
const httpLink = new HttpLink({uri: 'http://localhost:9000/graphql'})
const asyncAuthLink = setContext(
() => {
return new Promise((success, reject) => {
firebase.auth().currentUser.getToken().then(token => {
success({
headers: {
authorization: token ? `Bearer ${token}` : ''
}
})
}).catch(error => {
reject(error)
})
})
}
)
const authAfterware = onError(({networkError}) => {
if (networkError.statusCode === 401) AuthService.signout()
})
function createApolloClient() {
return new ApolloClient({
cache: new InMemoryCache(),
link: asyncAuthLink.concat(authAfterware.concat(httpLink))
})
}
Run Code Online (Sandbox Code Playgroud)
这在用户第一次进行身份验证时有效,但是一旦用户刷新页面,当我的 graphql 查询发送到我的后端时,firebase 不再被初始化,因此令牌不会随它一起发送。有没有一种方法可以异步等待,firebase.auth().currentUser这样就可以了?或者我应该完全采用另一种方法吗?据我所知(100% 确定)currentUser.getIdToken只有在当前令牌不再有效时才会进行网络调用。我认为这是可以接受的,因为在令牌无效的情况下,后端无论如何都无法响应,因此我需要等待令牌刷新才能继续。
我想到的其他一些想法:
localStorage存储身份验证令牌,authAfterware如果我的后端发回 401 响应并重试请求,则刷新它。谢谢!
小智 0
我知道有点晚了,但我也被困在这个问题上并找到了解决方法。也许不是最好的,但至少它有效。我的方法是创建一个 Next api 端点来使用 getUserFromCookies 方法检索用户令牌:
import { NextApiRequest, NextApiResponse } from "next";
import { getUserFromCookies } from "next-firebase-auth";
import initAuth from "../../utils/initAuth";
initAuth();
const handler = async (req: NextApiRequest, res: NextApiResponse<any>) => {
try {
const user = await getUserFromCookies({ req, includeToken: true });
const accessToken = await user.getIdToken();
return res.status(200).json({ success: true, accessToken });
} catch (e) {
console.log(`${e}`);
return res.status(500).json({ error: `Unexpected error. ${e}` });
}
};
export default handler;
Run Code Online (Sandbox Code Playgroud)
然后在 apollo 客户端配置中调用此端点,如下所示:
import { ApolloClient, InMemoryCache, ApolloLink, HttpLink, concat } from "@apollo/client";
import { setContext } from "@apollo/client/link/context";
import { relayStylePagination } from "@apollo/client/utilities";
const getUserToken = async () => {
const res = await fetch("http://localhost:3000/api/get-user-token");
const { accessToken } = await res.json();
return accessToken;
};
const asyncAuthLink = setContext(async (request) => {
const token = await getUserToken();
return { ...request, headers: { authorization: token ? `Bearer ${token}` : "" } };
});
const httpLink = new HttpLink({ uri: process.env.NEXT_PUBLIC_API_URL });
const client = new ApolloClient({
name: "web",
version: "1.0",
uri: process.env.NEXT_PUBLIC_API_URL,
cache: new InMemoryCache({
typePolicies: {
Query: {
fields: {
users: relayStylePagination(),
},
},
},
}),
link: concat(asyncAuthLink, httpLink),
});
export default client;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
380 次 |
| 最近记录: |