我是 React 和 Apollo Client 的新手,想开发一个基于令牌的安全认证。后端是用 Laravel 构建的。每次用户登录时,都会发送不记名令牌。我设法将令牌存储在反应 cookie 中。虽然我想实现一些场景:
如果我使用正确的凭据登录,则会生成一个令牌并将其存储在 cookie 中。现在我可以访问受保护的路由,因为用户已通过身份验证。这里我们有 3 个场景:
我想缓存有问题,但我不确定。你可以在下面找到我的
authContext.tsx
import React, { createContext, useState, useEffect } from 'react';
import { ME } from '../graphql/authentication/queries';
import { useCookies } from "react-cookie";
import { useApolloClient } from '@apollo/client';
interface AuthContextProps {
token: string | null,
loading: boolean,
isAuthenticated: boolean,
setAuthenticated: (authenticationToken: string) => void,
logout: () => void,
}
const TOKEN_NAME = "authToken";
const AuthContext = createContext<AuthContextProps>({
token: null,
loading: true,
isAuthenticated: false,
setAuthenticated: (authenticationToken: string) => { },
logout: () => { },
});
interface AuthProviderProps {
children: React.ReactNode;
}
const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
const [loading, setLoading] = useState<boolean>(true);
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
const [token, setToken] = useState<string | null>(null);
const [cookies, setCookie, removeCookie] = useCookies([TOKEN_NAME]);
const client = useApolloClient();
useEffect(() => {
const token = cookies[TOKEN_NAME];
if (token) {
const fetchUser = async () => {
try {
const { data } = await client.query({
query: ME,
fetchPolicy: 'network-only',
});
const me = data?.me;
console.log(me);
if (me) {
setIsAuthenticated(true);
setToken(token);
setLoading(false);
} else {
setIsAuthenticated(false);
setLoading(false);
}
} catch (error) {
setIsAuthenticated(false);
setLoading(false);
}
};
fetchUser();
} else {
setLoading(false);
}
}, [cookies, client]);
const setAuthenticated = (authenticationToken: string) => {
console.log(authenticationToken);
setCookie(TOKEN_NAME, authenticationToken, {
path: "/",
httpOnly: false, // set to true
sameSite: "strict",
maxAge: 60 * 60 * 24 * 30
});
setIsAuthenticated(true);
setLoading(true);
};
const logout = () => {
removeCookie(TOKEN_NAME);
client.clearStore();
client.resetStore();
setIsAuthenticated(false);
};
return (
<AuthContext.Provider
value={{
token,
loading,
isAuthenticated,
setAuthenticated,
logout,
}}
>
{children}
</AuthContext.Provider>
);
};
export { AuthContext, AuthProvider };
和我的客户
// @ts-nocheck
import { ApolloClient, InMemoryCache, HttpLink } from '@apollo/client';
import { getCSRFToken } from '../csrf-token';
import { Cookies } from 'react-cookie';
import { setContext } from '@apollo/client/link/context';
let csrfToken = await getCSRFToken();
const cookies = new Cookies();
let authToken = cookies.get('authToken');
console.log(authToken); // I can see the wrong token here
const authLink = setContext((_, { headers }) => {
return {
headers: {
...headers,
authorization: authToken ? `Bearer ${authToken}` : "",
}
}
});
const httpLink = new HttpLink({
uri: '[THE_URL]',
headers: {
"X-XSRF-TOKEN": csrfToken,
},
credentials: 'include',
});
const cache = new InMemoryCache({});
let client = new ApolloClient({
link: authLink.concat(httpLink),
cache: cache,
});
export default client;
我已经尝试在上下文中更新缓存(在
useEffect
中)但是除network-only
之外的任何其他内容都会导致应用程序将用户重定向到登录页面,尽管cookie中有正确的令牌。
最后,这是我的
index.tsx
档案
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { ApolloProvider } from '@apollo/client';
import { BrowserRouter } from 'react-router-dom';
import client from './apollo-client/apollo-client';
import { AuthProvider } from './context/authContext';
import { CookiesProvider } from 'react-cookie';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<ApolloProvider client={client}>
<CookiesProvider>
<BrowserRouter>
<AuthProvider>
<React.StrictMode>
<App />
</React.StrictMode>
</AuthProvider>
</BrowserRouter>
</CookiesProvider>
</ApolloProvider>
);
reportWebVitals();
提前谢谢你!如果您想从实施中获得更多背景信息,请告诉我