mirror of
https://github.com/strapi/strapi.git
synced 2025-08-13 19:27:34 +00:00
parent
5a845afdad
commit
785c4e862e
@ -8,28 +8,34 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { memo } from 'react';
|
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 PropTypes from 'prop-types';
|
||||||
import { auth } from '@strapi/helper-plugin';
|
import { auth } from '@strapi/helper-plugin';
|
||||||
|
|
||||||
/* eslint-disable react/jsx-curly-newline */
|
/* eslint-disable react/jsx-curly-newline */
|
||||||
|
|
||||||
const PrivateRoute = ({ component: Component, path, ...rest }) => (
|
const PrivateRoute = ({ component: Component, path, ...rest }) => {
|
||||||
<Route
|
const { pathname, search } = useLocation();
|
||||||
path={path}
|
|
||||||
render={props =>
|
return (
|
||||||
auth.getToken() !== null ? (
|
<Route
|
||||||
<Component {...rest} {...props} />
|
path={path}
|
||||||
) : (
|
render={props =>
|
||||||
<Redirect
|
auth.getToken() !== null ? (
|
||||||
to={{
|
<Component {...rest} {...props} />
|
||||||
pathname: '/auth/login',
|
) : (
|
||||||
}}
|
<Redirect
|
||||||
/>
|
to={{
|
||||||
)
|
pathname: '/auth/login',
|
||||||
}
|
search:
|
||||||
/>
|
pathname !== '/' && `?redirectTo=${encodeURIComponent(`${pathname}${search}`)}`,
|
||||||
);
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
PrivateRoute.propTypes = {
|
PrivateRoute.propTypes = {
|
||||||
component: PropTypes.any.isRequired,
|
component: PropTypes.any.isRequired,
|
||||||
|
@ -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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -14,7 +14,10 @@ import init from './init';
|
|||||||
import { initialState, reducer } from './reducer';
|
import { initialState, reducer } from './reducer';
|
||||||
|
|
||||||
const AuthPage = ({ hasAdmin, setHasAdmin }) => {
|
const AuthPage = ({ hasAdmin, setHasAdmin }) => {
|
||||||
const { push } = useHistory();
|
const {
|
||||||
|
push,
|
||||||
|
location: { search },
|
||||||
|
} = useHistory();
|
||||||
const { changeLocale } = useLocalesProvider();
|
const { changeLocale } = useLocalesProvider();
|
||||||
const { setSkipped } = useGuidedTour();
|
const { setSkipped } = useGuidedTour();
|
||||||
const { trackUsage } = useTracking();
|
const { trackUsage } = useTracking();
|
||||||
@ -119,7 +122,7 @@ const AuthPage = ({ hasAdmin, setHasAdmin }) => {
|
|||||||
auth.setToken(token, body.rememberMe);
|
auth.setToken(token, body.rememberMe);
|
||||||
auth.setUserInfo(user, body.rememberMe);
|
auth.setUserInfo(user, body.rememberMe);
|
||||||
|
|
||||||
push('/');
|
redirectToPreviousLocation();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err.response) {
|
if (err.response) {
|
||||||
const errorMessage = get(
|
const errorMessage = get(
|
||||||
@ -189,8 +192,7 @@ const AuthPage = ({ hasAdmin, setHasAdmin }) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect to the homePage
|
redirectToPreviousLocation();
|
||||||
push('/');
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
trackUsage('didNotCreateFirstAdmin');
|
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
|
// Redirect the user to the login page if
|
||||||
// the endpoint does not exist or
|
// the endpoint does not exist or
|
||||||
// there is already an admin user oo
|
// 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
|
// Redirect the user to the register-admin if it is the first user
|
||||||
if (!hasAdmin && authType !== 'register-admin') {
|
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 (
|
return (
|
||||||
|
Loading…
x
Reference in New Issue
Block a user