Preserve url if user's not logged in

Fix #12567
This commit is contained in:
Hung Viet Nguyen 2022-03-12 16:58:59 +07:00
parent 5a845afdad
commit 785c4e862e
No known key found for this signature in database
GPG Key ID: CAFDC50535B4A074
3 changed files with 114 additions and 22 deletions

View File

@ -8,28 +8,34 @@
*/
import React, { memo } from 'react';
import { Redirect, Route } from 'react-router-dom';
import { Redirect, Route, useLocation } from 'react-router-dom';
import PropTypes from 'prop-types';
import { auth } from '@strapi/helper-plugin';
/* eslint-disable react/jsx-curly-newline */
const PrivateRoute = ({ component: Component, path, ...rest }) => (
<Route
path={path}
render={props =>
auth.getToken() !== null ? (
<Component {...rest} {...props} />
) : (
<Redirect
to={{
pathname: '/auth/login',
}}
/>
)
}
/>
);
const PrivateRoute = ({ component: Component, path, ...rest }) => {
const { pathname, search } = useLocation();
return (
<Route
path={path}
render={props =>
auth.getToken() !== null ? (
<Component {...rest} {...props} />
) : (
<Redirect
to={{
pathname: '/auth/login',
search:
pathname !== '/' && `?redirectTo=${encodeURIComponent(`${pathname}${search}`)}`,
}}
/>
)
}
/>
);
};
PrivateRoute.propTypes = {
component: PropTypes.any.isRequired,

View File

@ -0,0 +1,69 @@
import React from 'react';
import { Router, Route, Switch } from 'react-router-dom';
import { createMemoryHistory } from 'history';
import { render, screen, waitFor } from '@testing-library/react';
import { auth } from '@strapi/helper-plugin';
import PrivateRoute from '..';
const ProtectedPage = () => {
return <div>You are authenticated</div>;
};
const LoginPage = () => {
return <div>Please login</div>;
};
const history = createMemoryHistory();
describe('PrivateRoute', () => {
const renderApp = () =>
render(
<Router history={history}>
<Switch>
<Route path="/auth/login" component={LoginPage} />
<PrivateRoute path="/" component={ProtectedPage} />
</Switch>
</Router>
);
afterEach(() => {
auth.clearToken();
});
it('Authenticated users should be able to access protected routes', async () => {
// Login
auth.setToken('access-token');
renderApp();
// Visit a protected route
history.push('/protected');
// Should see the protected route
expect(await screen.findByText('You are authenticated'));
});
it('Unauthenticated users should not be able to access protected routes and get redirected', async () => {
renderApp();
// Visit `/`
history.push('/');
// Should redirected to `/auth/login`
await waitFor(() => {
expect(history.location.pathname).toBe('/auth/login');
// No `redirectTo` in the search params
expect(history.location.search).toBe('');
expect(screen.getByText('Please login')).toBeInTheDocument();
});
// Visit /settings/application-infos
history.push('/settings/application-infos');
// Should redirected to `/auth/login` and preserve the `/settings/application-infos` path
await waitFor(() => {
expect(history.location.pathname).toBe('/auth/login');
// Should preserve url in the params
expect(history.location.search).toBe(
`?redirectTo=${encodeURIComponent('/settings/application-infos')}`
);
expect(screen.getByText('Please login')).toBeInTheDocument();
});
});
});

View File

@ -14,7 +14,10 @@ import init from './init';
import { initialState, reducer } from './reducer';
const AuthPage = ({ hasAdmin, setHasAdmin }) => {
const { push } = useHistory();
const {
push,
location: { search },
} = useHistory();
const { changeLocale } = useLocalesProvider();
const { setSkipped } = useGuidedTour();
const { trackUsage } = useTracking();
@ -119,7 +122,7 @@ const AuthPage = ({ hasAdmin, setHasAdmin }) => {
auth.setToken(token, body.rememberMe);
auth.setUserInfo(user, body.rememberMe);
push('/');
redirectToPreviousLocation();
} catch (err) {
if (err.response) {
const errorMessage = get(
@ -189,8 +192,7 @@ const AuthPage = ({ hasAdmin, setHasAdmin }) => {
return;
}
// Redirect to the homePage
push('/');
redirectToPreviousLocation();
} catch (err) {
trackUsage('didNotCreateFirstAdmin');
@ -238,6 +240,12 @@ const AuthPage = ({ hasAdmin, setHasAdmin }) => {
}
};
const redirectToPreviousLocation = () => {
const locationBeforeAuthenticated = decodeURIComponent(query.get('redirectTo'));
const redirectUrl = locationBeforeAuthenticated || '/';
push(redirectUrl);
};
// Redirect the user to the login page if
// the endpoint does not exist or
// there is already an admin user oo
@ -248,7 +256,16 @@ const AuthPage = ({ hasAdmin, setHasAdmin }) => {
// Redirect the user to the register-admin if it is the first user
if (!hasAdmin && authType !== 'register-admin') {
return <Redirect to="/auth/register-admin" />;
return (
<Redirect
to={{
pathname: '/auth/register-admin',
// Forward the `?redirectTo` from /auth/login
// /abc => /auth/login?redirectTo=%2Fabc => /auth/register-admin?redirectTo=%2Fabc
search,
}}
/>
);
}
return (