如何在 React Router v6.4
actions
和 loaders
中访问 Auth0 访问令牌,以便调用安全的 API?
我尝试将
getAccessTokenSilently()
方法柯里化到加载器,但我无法在组件外部调用 useAuth0()
钩子(我的路由是在组件外部创建的 如反应路由器文档所建议的)。出于同样的原因,我无法在加载器内调用 useAuth0()
:它不是组件。
我尝试将路由放入组件内(将下面代码中显示的路由移动到
<App/>
组件),但这会导致useAuth0()
出现错误,必须从Auth0Provider
内部调用它。
React Router v6的官方 Auth0 指南尚未更新为使用
createBrowserRouter
,并且在其安全 API 示例中没有使用加载器。
这似乎是任何 React Router v6.4 应用程序的基本需求,但我从未找到一个示例来说明如何做到这一点。肯定有人以前这样做过吗?
这是我的应用程序结构:
Auth0ProviderWithNavigate.tsx
interface Auth0ProviderWithNavigateProps {
children: React.ReactNode;
}
export const Auth0ProviderWithNavigate = ({
children,
}: Auth0ProviderWithNavigateProps) => {
if (
!(
ENV.VITE_AUTH0_DOMAIN &&
ENV.VITE_AUTH0_CLIENT_ID &&
ENV.VITE_AUTH0_CALLBACK_URL
)
) {
return null;
}
return (
<Auth0Provider
domain={ENV.VITE_AUTH0_DOMAIN}
clientId={ENV.VITE_AUTH0_CLIENT_ID}
authorizationParams={{
redirect_uri: ENV.VITE_AUTH0_CALLBACK_URL,
}}
>
{children}
</Auth0Provider>
);
};
AuthenticationGuard.tsx
import { withAuthenticationRequired } from "@auth0/auth0-react";
import { PageLoader } from "./PageLoader";
interface AuthenticationGuardProps {
component: React.ComponentType<object>;
}
export const AuthenticationGuard = ({
component,
}: AuthenticationGuardProps) => {
const Component = withAuthenticationRequired(component, {
onRedirecting: () => <PageLoader />,
});
return <Component />;
};
main.tsx
const root = document.getElementById("root");
root &&
ReactDOM.createRoot(root).render(
<React.StrictMode>
<AppContextProvider>
<Auth0ProviderWithNavigate>
<AppTheme>
<App />
</AppTheme>
</Auth0ProviderWithNavigate>
</AppContextProvider>
</React.StrictMode>
);
App.tsx
const router = createBrowserRouter([
{
children: [
{
path: "/",
element: <WelcomePage />,
errorElement: <ErrorPage />,
},
{
children: [
{
id: "edct",
path: "/edct",
element: <AuthenticationGuard component={Edct} />,
errorElement: <ErrorPage />,
loader: AirportCodesLoader,
},
],
},
],
},
]);
const App = () => {
return <RouterProvider router={router} />;
};
export default App;
AirportCodesLoader.tsx
import { LoaderFunction } from "react-router";
export const AirportCodesLoader: LoaderFunction = ({ request }) => {
const url = new URL(request.url);
// Use token here to call a REST API using query params
// from the URL
};
是的,虽然在 React 树之外声明路由器配置是常见的做法,但这只是一个建议。在这种情况下,您可以在
App
组件内创建它,以便它可以关闭要传递给路由加载器的 auth0
上下文值的实例。需要接收 auth0
上下文的路由加载器需要柯里化该参数。
示例:
const AirportCodesLoader = (auth0) => ({ params, request }) => {
... loader logic ...
};
const App = () => {
const auth0 = useAuth0();
const router = React.useMemo(() => { // <-- memoize router reference
return createBrowserRouter([
{
children: [
{
path: "/",
element: <WelcomePage />,
errorElement: <ErrorPage />,
},
{
children: [
{
id: "edct",
path: "/edct",
element: <AuthenticationGuard component={Edct} />,
errorElement: <ErrorPage />,
loader: AirportCodesLoader(auth0), // <-- pass auth0 to loader
},
],
},
],
},
]);
}, [auth0]); // <-- auth0 external dependency
return <RouterProvider router={router} />;
};