¿Alguien sabe cómo restringir el acceso a rutas particulares en react-router? Quiero comprobar si el usuario está conectado antes de permitir el acceso a una ruta en particular. Pensé que sería simple, pero los documentos no tienen claro cómo hacerlo.
¿Es esto algo que debería configurar donde defino mis <Route>
componentes, o debería manejarlo dentro de mis controladores de componentes?
<Route handler={App} path="/">
<NotFoundRoute handler={NotFound} name="not-found"/>
<DefaultRoute handler={Login} name="login"/>
<Route handler={Todos} name="todos"/> {/* I want this to be restricted */}
</Route>
javascript
reactjs
react-router
Tanner Semerad
fuente
fuente
Respuestas:
Actualización (16 de agosto de 2019)
En react-router v4 y usando React Hooks, esto se ve un poco diferente. Empecemos con tu
App.js
.export default function App() { const [isAuthenticated, userHasAuthenticated] = useState(false); useEffect(() => { onLoad(); }, []); async function onLoad() { try { await Auth.currentSession(); userHasAuthenticated(true); } catch (e) { alert(e); } } return ( <div className="App container"> <h1>Welcome to my app</h1> <Switch> <UnauthenticatedRoute path="/login" component={Login} appProps={{ isAuthenticated }} /> <AuthenticatedRoute path="/todos" component={Todos} appProps={{ isAuthenticated }} /> <Route component={NotFound} /> </Switch> </div> ); }
Estamos usando una
Auth
biblioteca para verificar si el usuario está autenticado actualmente. Reemplace esto con su función de verificación de autenticación. Si es así, establecemos laisAuthenticated
bandera entrue
. Hacemos esto cuando nuestra aplicación se carga por primera vez. También vale la pena mencionar que es posible que desee agregar un signo de carga en su aplicación mientras se ejecuta la verificación de autenticación, para que no muestre la página de inicio de sesión cada vez que actualice la página.Luego pasamos la bandera a nuestras rutas. Creamos dos tipos de rutas
AuthenticatedRoute
yUnauthenticatedRoute
.Se
AuthenticatedRoute.js
ve así.export default function AuthenticatedRoute({ component: C, appProps, ...rest }) { return ( <Route {...rest} render={props => appProps.isAuthenticated ? <C {...props} {...appProps} /> : <Redirect to={`/login?redirect=${props.location.pathname}${props.location.search}`} />} /> ); }
Comprueba si
isAuthenticated
está configurado entrue
. Si es así, renderizará el componente deseado. De lo contrario, redirigirá a la página de inicio de sesión.El
UnauthenticatedRoute.js
por otro lado se ve así.export default ({ component: C, appProps, ...rest }) => <Route {...rest} render={props => !appProps.isAuthenticated ? <C {...props} {...appProps} /> : <Redirect to="/" />} />;
En este caso, si
isAuthenticated
está configurado enfalse
, renderizará el componente deseado. Y si está configurado como verdadero, lo enviará a la página de inicio.Puede encontrar versiones detalladas de esto en nuestra guía: https://serverless-stack.com/chapters/create-a-route-that-redirects.html .
Versión antigua
La respuesta aceptada es correcta, pero el equipo de React considera que los Mixins son dañinos ( https://facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html ).
Si alguien se encuentra con esta pregunta y está buscando la forma recomendada de hacerlo, le sugiero que use Componentes de orden superior en lugar de Mixins.
Aquí hay un ejemplo de un HOC que verificará si el usuario inició sesión antes de continuar. Y si el usuario no ha iniciado sesión, lo redireccionará a la página de inicio de sesión. Este componente toma un accesorio llamado
isLoggedIn
, que es básicamente una bandera que su aplicación puede almacenar para indicar si el usuario está conectado.import React from 'react'; import { withRouter } from 'react-router'; export default function requireAuth(Component) { class AuthenticatedComponent extends React.Component { componentWillMount() { this.checkAuth(); } checkAuth() { if ( ! this.props.isLoggedIn) { const location = this.props.location; const redirect = location.pathname + location.search; this.props.router.push(`/login?redirect=${redirect}`); } } render() { return this.props.isLoggedIn ? <Component { ...this.props } /> : null; } } return withRouter(AuthenticatedComponent); }
Y para usar este HOC, simplemente envuélvalo en sus rutas. En el caso de su ejemplo, sería:
<Route handler={requireAuth(Todos)} name="todos"/>
Cubro este y algunos otros temas en un tutorial detallado paso a paso aquí: https://serverless-stack.com/chapters/create-a-hoc-that-checks-auth.html
fuente
this.props.isLoggedIn
contrue
y entrada de derivación?<Route handler={}/>
está en desuso en v1.0, debe usar<Route component={} />
.componentWillMount
pronto quedarán obsoletos. Léalo en la publicación del blog en reactjs.org . En su lugar, iría con la respuesta que @jacob proporcionó.Hay (¿ahora?) Un ejemplo de esto en los documentos de React Router 4 para
Redirect
import { Route, Redirect } from 'react-router' <Route exact path="/" render={() => ( loggedIn ? ( <Redirect to="/dashboard"/> ) : ( <PublicHomePage/> ) )}/>
fuente
Si desea utilizar la autenticación en toda su aplicación, debe almacenar algunos datos en toda la aplicación (por ejemplo, token). Puede configurar dos mixins de React que sean responsables de administrar el
$auth
objeto. Este objeto no debería estar disponible fuera de esos dos mixins. Aquí hay un ejemplo de eso:define('userManagement', function() { 'use strict'; var $auth = { isLoggedIn: function () { // return something, e.g. using server-stored data } }; return { Authenticator: { login: function(username, password) { // modify $auth object, or call server, or both } }, NeedsAuthenticatedUser: { statics: { willTransitionTo: function (transition) { if (!$auth.isLoggedIn()) { transition.abort(); } } } } }; });
Luego, puede simplemente
Authenticator
mezclar la mezcla con sus componentes de inicio de sesión (pantalla de inicio de sesión, ventana emergente de inicio de sesión, etc.) y llamar a lathis.login
función cuando tenga todos los datos necesarios.Lo más importante es proteger sus componentes mezclándolos con
NeedsAuthenticatedUser
mixin. Cada componente que necesita un usuario autenticado tendrá que verse así:var um = require('userManagement'); var ProtectedComponent = React.createClass({ mixins: [um.NeedsAuthenticatedUser] // ... }
Tenga en cuenta que
NeedsAuthenticatedUser
utiliza la API react-router (willTransitionTo
ytransition.abort()
).fuente
react-router
fomenta un enfoque declarativo para su enrutador, debe hacer que su enrutador sea lo más tonto posible y evitar poner su lógica de enrutamiento en sus componentes.Así es como puede hacerlo (suponiendo que le pase el
loggedIn
accesorio):const DumbRouter = ({ loggedIn }) => ( <Router history={history}> <Switch> {[ !loggedIn && LoggedOutRoutes, loggedIn && LoggedInRouter, <Route component={404Route} /> ]} </Switch> </Router> ); const LoggedInRoutes = [ <Route path="/" component={Profile} /> ]; const LoggedOutRoutes = [ <Route path="/" component={Login} /> ];
fuente
Puede usar HOC y auth es una variable que puede cambiar el valor verdadero o falso significa (autorización)
<Route path="/login" component={SignIn} /> <Route path="/posts" render = {() => (auth ? (<Post />) : (<Redirect to="/login" />))}/>
fuente
ruta-privada.tsx
import {Redirect, Route, RouteProps} from 'react-router'; import * as React from 'react'; interface PrivateRouteProps extends RouteProps { /** * '/login' for example. */ redirectTo: string; /** * If true, won't redirect. * We are using a function instead of a bool, a bool does not seem to be updated * after having successfully authenticated. */ isLogged: () => boolean; } export function PrivateRoute(props: PrivateRouteProps) { // `component: Component` is not typing, it assign the value to a new variable. let { isLogged, redirectTo, component: Component, ...rest }: any = props; // error: JSX type element Component does not have call signature or ... AVOIDED BY ADDING ANY, still work, // and did not find a proper way to fix it. return <Route {...rest} render={(props) => ( isLogged() ? <Component {...props}/> : <Redirect to={{ pathname: redirectTo, state: { from: props.location } }} /> )} />; }
Uso:
<PrivateRoute exact={true} path="/admin/" redirectTo={'/admin/login'} isLogged={this.loginService.isLogged} component={AdminDashboardPage}/> <Route path="/admin/login/" component={AdminLoginPage}/>
Basado en https://tylermcginnis.com/react-router-protected-routes-authentication/ .
fuente
Por lo general, a un usuario que haya iniciado sesión se le otorgará un token y utilizará este token para cualquier comunicación con el servidor. Lo que solemos hacer es definir una página raíz y las cosas se construyen sobre esa página. esta página raíz realiza la localización, autenticación y otras configuraciones por usted.
aquí hay un ejemplo
Routes = ( <Route path="/" handler={Root}> <Route name="login" handler={Login} /> <Route name="forget" handler={ForgetPassword} /> <Route handler={Main} > <Route name="overview" handler={Overview} /> <Route name="profile" handler={Profile} /> <DefaultRoute handler={Overview} /> </Route> <DefaultRoute handler={Login} /> <NotFoundRoute handler={NotFound} /> </Route> );
en su página raíz, verifique que el token sea nulo o autentique el token con el servidor para ver si el usuario tiene un inicio de sesión válido.
espero que esto ayude :)
fuente