0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-01-06 20:40:08 -05:00

refactor(console): align sign-in/out redirect uris (#4385)

This commit is contained in:
Gao Sun 2023-08-23 22:53:48 +08:00 committed by GitHub
parent 7b569a4de9
commit 53486f27ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 37 additions and 26 deletions

View file

@ -1,8 +1,7 @@
import { useLogto } from '@logto/react'; import { useLogto } from '@logto/react';
import { useContext, useEffect } from 'react'; import { useEffect } from 'react';
import { getCallbackUrl } from '@/consts'; import useRedirectUri from '@/hooks/use-redirect-uri';
import { TenantsContext } from '@/contexts/TenantsProvider';
import { saveRedirect } from '@/utils/storage'; import { saveRedirect } from '@/utils/storage';
import AppLoading from '../AppLoading'; import AppLoading from '../AppLoading';
@ -10,14 +9,14 @@ import AppLoading from '../AppLoading';
/** This component shows a loading indicator and tries to sign in again. */ /** This component shows a loading indicator and tries to sign in again. */
function SessionExpired() { function SessionExpired() {
const { signIn, isLoading } = useLogto(); const { signIn, isLoading } = useLogto();
const { currentTenantId } = useContext(TenantsContext); const redirectUri = useRedirectUri();
useEffect(() => { useEffect(() => {
if (!isLoading) { if (!isLoading) {
saveRedirect(); saveRedirect();
void signIn(getCallbackUrl(currentTenantId).href); void signIn(redirectUri.href);
} }
}, [signIn, isLoading, currentTenantId]); }, [signIn, isLoading, redirectUri]);
return <AppLoading />; return <AppLoading />;
} }

View file

@ -1,6 +1,3 @@
import { ossConsolePath } from '@logto/schemas';
import { conditionalArray } from '@silverhand/essentials';
import { adminEndpoint, isCloud } from './env'; import { adminEndpoint, isCloud } from './env';
const getAdminTenantEndpoint = () => { const getAdminTenantEndpoint = () => {
@ -17,12 +14,3 @@ const getAdminTenantEndpoint = () => {
export const adminTenantEndpoint = getAdminTenantEndpoint(); export const adminTenantEndpoint = getAdminTenantEndpoint();
export const mainTitle = isCloud ? 'Logto Cloud' : 'Logto Console'; export const mainTitle = isCloud ? 'Logto Cloud' : 'Logto Console';
export const getCallbackUrl = (tenantId?: string) =>
new URL(
// Only Cloud has tenantId in callback URL
'/' + conditionalArray(isCloud ? tenantId : 'console', 'callback').join('/'),
window.location.origin
);
export const getSignOutRedirectPathname = () => (isCloud ? '/' : ossConsolePath);

View file

@ -11,12 +11,12 @@ import Profile from '@/assets/icons/profile.svg';
import SignOut from '@/assets/icons/sign-out.svg'; import SignOut from '@/assets/icons/sign-out.svg';
import UserAvatar from '@/components/UserAvatar'; import UserAvatar from '@/components/UserAvatar';
import UserInfoCard from '@/components/UserInfoCard'; import UserInfoCard from '@/components/UserInfoCard';
import { getSignOutRedirectPathname } from '@/consts';
import Divider from '@/ds-components/Divider'; import Divider from '@/ds-components/Divider';
import Dropdown, { DropdownItem } from '@/ds-components/Dropdown'; import Dropdown, { DropdownItem } from '@/ds-components/Dropdown';
import Spacer from '@/ds-components/Spacer'; import Spacer from '@/ds-components/Spacer';
import { Ring as Spinner } from '@/ds-components/Spinner'; import { Ring as Spinner } from '@/ds-components/Spinner';
import useCurrentUser from '@/hooks/use-current-user'; import useCurrentUser from '@/hooks/use-current-user';
import useRedirectUri from '@/hooks/use-redirect-uri';
import useTenantPathname from '@/hooks/use-tenant-pathname'; import useTenantPathname from '@/hooks/use-tenant-pathname';
import useUserPreferences from '@/hooks/use-user-preferences'; import useUserPreferences from '@/hooks/use-user-preferences';
import { DynamicAppearanceMode } from '@/types/appearance-mode'; import { DynamicAppearanceMode } from '@/types/appearance-mode';
@ -33,6 +33,7 @@ function UserInfo() {
const { user, isLoading: isLoadingUser } = useCurrentUser(); const { user, isLoading: isLoadingUser } = useCurrentUser();
const anchorRef = useRef<HTMLDivElement>(null); const anchorRef = useRef<HTMLDivElement>(null);
const [showDropdown, setShowDropdown] = useState(false); const [showDropdown, setShowDropdown] = useState(false);
const postSignOutRedirectUri = useRedirectUri('signOut');
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const { const {
@ -128,7 +129,7 @@ function UserInfo() {
return; return;
} }
setIsLoading(true); setIsLoading(true);
void signOut(new URL(getSignOutRedirectPathname(), window.location.origin).toString()); void signOut(postSignOutRedirectUri.href);
}} }}
> >
{t('menu.sign_out')} {t('menu.sign_out')}

View file

@ -5,8 +5,9 @@ import { Outlet, useSearchParams } from 'react-router-dom';
import { useCloudApi } from '@/cloud/hooks/use-cloud-api'; import { useCloudApi } from '@/cloud/hooks/use-cloud-api';
import AppLoading from '@/components/AppLoading'; import AppLoading from '@/components/AppLoading';
import { searchKeys, getCallbackUrl } from '@/consts'; import { searchKeys } from '@/consts';
import { TenantsContext } from '@/contexts/TenantsProvider'; import { TenantsContext } from '@/contexts/TenantsProvider';
import useRedirectUri from '@/hooks/use-redirect-uri';
import { saveRedirect } from '@/utils/storage'; import { saveRedirect } from '@/utils/storage';
/** /**
@ -32,15 +33,16 @@ export default function ProtectedRoutes() {
const api = useCloudApi(); const api = useCloudApi();
const [searchParameters] = useSearchParams(); const [searchParameters] = useSearchParams();
const { isAuthenticated, isLoading, signIn } = useLogto(); const { isAuthenticated, isLoading, signIn } = useLogto();
const { currentTenantId, isInitComplete, resetTenants } = useContext(TenantsContext); const { isInitComplete, resetTenants } = useContext(TenantsContext);
const redirectUri = useRedirectUri();
useEffect(() => { useEffect(() => {
if (!isLoading && !isAuthenticated) { if (!isLoading && !isAuthenticated) {
saveRedirect(); saveRedirect();
const isSignUpMode = yes(searchParameters.get(searchKeys.signUp)); const isSignUpMode = yes(searchParameters.get(searchKeys.signUp));
void signIn(getCallbackUrl(currentTenantId).href, conditional(isSignUpMode && 'signUp')); void signIn(redirectUri.href, conditional(isSignUpMode && 'signUp'));
} }
}, [currentTenantId, isAuthenticated, isLoading, searchParameters, signIn]); }, [redirectUri, isAuthenticated, isLoading, searchParameters, signIn]);
useEffect(() => { useEffect(() => {
if (isAuthenticated && !isInitComplete) { if (isAuthenticated && !isInitComplete) {

View file

@ -0,0 +1,20 @@
import { ossConsolePath } from '@logto/schemas';
import { conditionalArray } from '@silverhand/essentials';
import { useHref } from 'react-router-dom';
import { isCloud } from '@/consts/env';
/**
* The hook that returns the absolute URL for the sign-in or sign-out callback.
* The path is not related to react-router, which means the path will also include
* the basename of react-router if it's set.
*/
const useRedirectUri = (flow: 'signIn' | 'signOut' = 'signIn') => {
const path = useHref(
conditionalArray(!isCloud && ossConsolePath, flow === 'signIn' && '/callback').join('')
);
return new URL(path, window.location.origin);
};
export default useRedirectUri;

View file

@ -4,8 +4,8 @@ import { useEffect } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import Logo from '@/assets/images/logo.svg'; import Logo from '@/assets/images/logo.svg';
import { getCallbackUrl } from '@/consts';
import Button from '@/ds-components/Button'; import Button from '@/ds-components/Button';
import useRedirectUri from '@/hooks/use-redirect-uri';
import useTenantPathname from '@/hooks/use-tenant-pathname'; import useTenantPathname from '@/hooks/use-tenant-pathname';
import useTheme from '@/hooks/use-theme'; import useTheme from '@/hooks/use-theme';
@ -16,6 +16,7 @@ function Welcome() {
const { navigate } = useTenantPathname(); const { navigate } = useTenantPathname();
const { isAuthenticated, signIn } = useLogto(); const { isAuthenticated, signIn } = useLogto();
const theme = useTheme(); const theme = useTheme();
const redirectUri = useRedirectUri();
useEffect(() => { useEffect(() => {
// If authenticated, navigate to the console root page directly // If authenticated, navigate to the console root page directly
@ -40,7 +41,7 @@ function Welcome() {
type="branding" type="branding"
title="welcome.create_account" title="welcome.create_account"
onClick={() => { onClick={() => {
void signIn(getCallbackUrl().href); void signIn(redirectUri.href);
}} }}
/> />
</div> </div>