From 14be568c7326a6e13764c0a8ce9bbb9cfbaaadbe Mon Sep 17 00:00:00 2001 From: shaoyu Date: Wed, 20 Jul 2022 20:59:18 -0500 Subject: [PATCH 1/6] update auth to support pessimistic mode --- docs/Authenticated.md | 2 +- packages/ra-core/src/auth/Authenticated.tsx | 27 ++++++++++++++------- packages/ra-core/src/auth/useAuthState.ts | 7 ++++-- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/docs/Authenticated.md b/docs/Authenticated.md index 535f4a2c2e7..8eed68d52a7 100644 --- a/docs/Authenticated.md +++ b/docs/Authenticated.md @@ -5,7 +5,7 @@ title: "The Authenticated Component" # `` -The `` component calls [the `useAuthenticated()` hook](./useAuthenticated.md), and renders its child component - unless the authentication check fails. Use it as an alternative to the `useAuthenticated()` hook when you can't use a hook, e.g. inside a `` commponent: +The `` component calls [the `useAuthState()` hook](./useAuthState.md), and renders its child component - unless the authentication check fails. Use it as an alternative to the `useAuthenticated()` hook when you can't use a hook, e.g. inside a `` commponent: ```jsx import { Admin, CustomRoutes, Authenticated } from 'react-admin'; diff --git a/packages/ra-core/src/auth/Authenticated.tsx b/packages/ra-core/src/auth/Authenticated.tsx index 95d8ccbc405..0e4b221f6e5 100644 --- a/packages/ra-core/src/auth/Authenticated.tsx +++ b/packages/ra-core/src/auth/Authenticated.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { ReactNode } from 'react'; -import { useAuthenticated } from './useAuthenticated'; +import { useAuthState } from './useAuthState'; /** * Restrict access to children to authenticated users. @@ -13,33 +13,42 @@ import { useAuthenticated } from './useAuthenticated'; * You can set additional `authParams` at will if your authProvider * requires it. * - * @see useAuthenticated + * @see useAuthState * * @example * import { Authenticated } from 'react-admin'; * * const CustomRoutes = [ - * + * * * * } /> * ]; * const App = () => ( - * - * ... + * + * {CustomRoutes} * * ); */ export const Authenticated = (props: AuthenticatedProps) => { - const { authParams, children } = props; - useAuthenticated({ params: authParams }); - // render the child even though the useAuthenticated() call isn't finished (optimistic rendering) - // the above hook will log out if the authProvider doesn't validate that the user is authenticated + const { authParams, children, pessimistic = false } = props; + + // this hook will log out if the authProvider doesn't validate that the user is authenticated + const { isLoading, authenticated } = useAuthState(authParams, true); + + // to prevent flash of UI, we don't render the children + // in pessimistic mode until the authProvider has validated the user + if (!authenticated || (pessimistic && isLoading)) { + return null; + } + + // render the children when authenticated or when in optimistic mode (default) return <>{children}; }; export interface AuthenticatedProps { children: ReactNode; authParams?: object; + pessimistic?: boolean; } diff --git a/packages/ra-core/src/auth/useAuthState.ts b/packages/ra-core/src/auth/useAuthState.ts index 1ef3263f8c4..8bd0c4b851a 100644 --- a/packages/ra-core/src/auth/useAuthState.ts +++ b/packages/ra-core/src/auth/useAuthState.ts @@ -45,14 +45,17 @@ const emptyParams = {}; * return ; * }; */ -const useAuthState = (params: any = emptyParams): State => { +const useAuthState = ( + params: any = emptyParams, + logoutOnFailure: boolean = false +): State => { const [state, setState] = useSafeSetState({ isLoading: true, authenticated: true, // optimistic }); const checkAuth = useCheckAuth(); useEffect(() => { - checkAuth(params, false) + checkAuth(params, logoutOnFailure) .then(() => setState({ isLoading: false, authenticated: true })) .catch(() => setState({ isLoading: false, authenticated: false })); }, [checkAuth, params, setState]); From 8d3221539335c1f93497f295d194e83ccdefa8a1 Mon Sep 17 00:00:00 2001 From: shaoyu Date: Wed, 20 Jul 2022 21:28:36 -0500 Subject: [PATCH 2/6] fix examples --- packages/ra-core/src/auth/Authenticated.tsx | 19 +++++++++++-------- packages/ra-core/src/auth/useAuthenticated.ts | 10 +++++----- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/packages/ra-core/src/auth/Authenticated.tsx b/packages/ra-core/src/auth/Authenticated.tsx index 0e4b221f6e5..5929e3b3e28 100644 --- a/packages/ra-core/src/auth/Authenticated.tsx +++ b/packages/ra-core/src/auth/Authenticated.tsx @@ -16,18 +16,21 @@ import { useAuthState } from './useAuthState'; * @see useAuthState * * @example - * import { Authenticated } from 'react-admin'; + * import { Admin, CustomRoutes, Authenticated } from 'react-admin'; * - * const CustomRoutes = [ - * - * - * - * } /> + * const customRoutes = [ + * + * + * + * } + * /> * ]; * const App = () => ( * - * {CustomRoutes} + * {customRoutes} * * ); */ diff --git a/packages/ra-core/src/auth/useAuthenticated.ts b/packages/ra-core/src/auth/useAuthenticated.ts index 75fa3cfe605..83a3e1d573c 100644 --- a/packages/ra-core/src/auth/useAuthenticated.ts +++ b/packages/ra-core/src/auth/useAuthenticated.ts @@ -12,17 +12,17 @@ import { useCheckAuth } from './useCheckAuth'; * requires it. * * @example - * import { useAuthenticated } from 'react-admin'; + * import { Admin, CustomRoutes, useAuthenticated } from 'react-admin'; * const FooPage = () => { * useAuthenticated(); * return ; * } - * const CustomRoutes = [ - * } /> + * const customRoutes = [ + * } /> * ]; * const App = () => ( - * - * ... + * + * {customRoutes} * * ); */ From 24d57f67cf691eb9d086045de1e3f71ff354b22c Mon Sep 17 00:00:00 2001 From: shaoyu Date: Thu, 21 Jul 2022 04:54:09 +0000 Subject: [PATCH 3/6] update imports --- packages/ra-core/src/auth/Authenticated.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/ra-core/src/auth/Authenticated.tsx b/packages/ra-core/src/auth/Authenticated.tsx index 5929e3b3e28..663c6961b92 100644 --- a/packages/ra-core/src/auth/Authenticated.tsx +++ b/packages/ra-core/src/auth/Authenticated.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { ReactNode } from 'react'; -import { useAuthState } from './useAuthState'; +import useAuthState from './useAuthState'; /** * Restrict access to children to authenticated users. @@ -10,6 +10,10 @@ import { useAuthState } from './useAuthState'; * Use it to decorate your custom page components to require * authentication. * + * By default this component is optimistic: it does not block + * rendering children when checking authentication, but this mode + * can be turned off by setting `pessimistic` to true. + * * You can set additional `authParams` at will if your authProvider * requires it. * @@ -40,13 +44,12 @@ export const Authenticated = (props: AuthenticatedProps) => { // this hook will log out if the authProvider doesn't validate that the user is authenticated const { isLoading, authenticated } = useAuthState(authParams, true); - // to prevent flash of UI, we don't render the children - // in pessimistic mode until the authProvider has validated the user - if (!authenticated || (pessimistic && isLoading)) { + // in pessimistic mode don't render the children until authenticated + if ((pessimistic && isLoading) || !authenticated) { return null; } - // render the children when authenticated or when in optimistic mode (default) + // render the children in optimistic rendering or after authenticated return <>{children}; }; From f18005a9e750e5dbe55bf244b507a54ee5f7aa8a Mon Sep 17 00:00:00 2001 From: smeng9 <38666763+smeng9@users.noreply.github.com> Date: Thu, 21 Jul 2022 00:09:54 -0500 Subject: [PATCH 4/6] update docs --- docs/Authenticated.md | 4 ++-- packages/ra-core/src/auth/useAuthState.ts | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/Authenticated.md b/docs/Authenticated.md index 8eed68d52a7..5cd170c00cc 100644 --- a/docs/Authenticated.md +++ b/docs/Authenticated.md @@ -5,7 +5,7 @@ title: "The Authenticated Component" # `` -The `` component calls [the `useAuthState()` hook](./useAuthState.md), and renders its child component - unless the authentication check fails. Use it as an alternative to the `useAuthenticated()` hook when you can't use a hook, e.g. inside a `` commponent: +The `` component calls [the `useAuthState()` hook](./useAuthState.md), and by default optimistically renders its child component - unless the authentication check fails. Use it as an alternative to the `useAuthenticated()` hook when you can't use a hook, or you want to support pessimistic mode, e.g. inside a `` commponent: ```jsx import { Admin, CustomRoutes, Authenticated } from 'react-admin'; @@ -15,7 +15,7 @@ const App = () => ( } /> - } /> + } /> } /> diff --git a/packages/ra-core/src/auth/useAuthState.ts b/packages/ra-core/src/auth/useAuthState.ts index 8bd0c4b851a..c4f32442763 100644 --- a/packages/ra-core/src/auth/useAuthState.ts +++ b/packages/ra-core/src/auth/useAuthState.ts @@ -28,6 +28,8 @@ const emptyParams = {}; * @see useAuthenticated() * * @param {Object} params Any params you want to pass to the authProvider + * + * @param {Boolean} logoutOnFailure: Optional. Whether the user should be logged out if the authProvider fails to authenticate them. False by default. * * @returns The current auth check state. Destructure as { authenticated, error, isLoading }. * From b8b5b5b9b820a31269cdfdc9e16d627bd50fefbd Mon Sep 17 00:00:00 2001 From: smeng9 <38666763+smeng9@users.noreply.github.com> Date: Thu, 21 Jul 2022 00:43:22 -0500 Subject: [PATCH 5/6] fix linter --- packages/ra-core/src/auth/useAuthState.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ra-core/src/auth/useAuthState.ts b/packages/ra-core/src/auth/useAuthState.ts index c4f32442763..635d6af4be4 100644 --- a/packages/ra-core/src/auth/useAuthState.ts +++ b/packages/ra-core/src/auth/useAuthState.ts @@ -28,7 +28,7 @@ const emptyParams = {}; * @see useAuthenticated() * * @param {Object} params Any params you want to pass to the authProvider - * + * * @param {Boolean} logoutOnFailure: Optional. Whether the user should be logged out if the authProvider fails to authenticate them. False by default. * * @returns The current auth check state. Destructure as { authenticated, error, isLoading }. @@ -60,7 +60,7 @@ const useAuthState = ( checkAuth(params, logoutOnFailure) .then(() => setState({ isLoading: false, authenticated: true })) .catch(() => setState({ isLoading: false, authenticated: false })); - }, [checkAuth, params, setState]); + }, [checkAuth, params, logoutOnFailure, setState]); return state; }; From c5f6ba0f0f973917e55cd130deb7e3df338be663 Mon Sep 17 00:00:00 2001 From: smeng9 <38666763+smeng9@users.noreply.github.com> Date: Thu, 21 Jul 2022 03:40:28 -0500 Subject: [PATCH 6/6] rename prop to requireAuth --- docs/Authenticated.md | 4 ++-- packages/ra-core/src/auth/Authenticated.tsx | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/Authenticated.md b/docs/Authenticated.md index 5cd170c00cc..f31e01ba4e4 100644 --- a/docs/Authenticated.md +++ b/docs/Authenticated.md @@ -5,7 +5,7 @@ title: "The Authenticated Component" # `` -The `` component calls [the `useAuthState()` hook](./useAuthState.md), and by default optimistically renders its child component - unless the authentication check fails. Use it as an alternative to the `useAuthenticated()` hook when you can't use a hook, or you want to support pessimistic mode, e.g. inside a `` commponent: +The `` component calls [the `useAuthState()` hook](./useAuthState.md), and by default optimistically renders its child component - unless the authentication check fails. Use it as an alternative to the `useAuthenticated()` hook when you can't use a hook, or you want to support pessimistic mode by setting `requireAuth` prop, e.g. inside a `` commponent: ```jsx import { Admin, CustomRoutes, Authenticated } from 'react-admin'; @@ -15,7 +15,7 @@ const App = () => ( } /> - } /> + } /> } /> diff --git a/packages/ra-core/src/auth/Authenticated.tsx b/packages/ra-core/src/auth/Authenticated.tsx index 663c6961b92..11fe00565ac 100644 --- a/packages/ra-core/src/auth/Authenticated.tsx +++ b/packages/ra-core/src/auth/Authenticated.tsx @@ -12,7 +12,7 @@ import useAuthState from './useAuthState'; * * By default this component is optimistic: it does not block * rendering children when checking authentication, but this mode - * can be turned off by setting `pessimistic` to true. + * can be turned off by setting `requireAuth` to true. * * You can set additional `authParams` at will if your authProvider * requires it. @@ -39,13 +39,13 @@ import useAuthState from './useAuthState'; * ); */ export const Authenticated = (props: AuthenticatedProps) => { - const { authParams, children, pessimistic = false } = props; + const { authParams, children, requireAuth = false } = props; // this hook will log out if the authProvider doesn't validate that the user is authenticated const { isLoading, authenticated } = useAuthState(authParams, true); // in pessimistic mode don't render the children until authenticated - if ((pessimistic && isLoading) || !authenticated) { + if ((requireAuth && isLoading) || !authenticated) { return null; } @@ -56,5 +56,5 @@ export const Authenticated = (props: AuthenticatedProps) => { export interface AuthenticatedProps { children: ReactNode; authParams?: object; - pessimistic?: boolean; + requireAuth?: boolean; }