Czy ktoś wie, jak ograniczyć dostęp do określonych tras w routerze reagującym? Chcę sprawdzić, czy użytkownik jest zalogowany przed zezwoleniem na dostęp do określonej trasy. Myślałem, że to będzie proste, ale dokumentacja nie jest jasna, jak to zrobić.
Czy jest to coś, co powinienem skonfigurować, gdzie definiuję moje <Route>
komponenty, czy powinienem obsługiwać to w moich programach obsługi składników?
<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
źródło
źródło
Odpowiedzi:
Aktualizacja (16 sierpnia 2019 r.)
W React-router v4 i korzystaniu z React Hooks wygląda to trochę inaczej. Zacznijmy od twojego
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> ); }
Używamy
Auth
biblioteki, aby sprawdzić, czy użytkownik jest aktualnie uwierzytelniony. Zastąp to funkcją sprawdzania autoryzacji. Jeśli tak, ustawiamyisAuthenticated
flagę natrue
. Robimy to po pierwszym załadowaniu naszej aplikacji. Warto również wspomnieć, że możesz chcieć dodać znak ładowania do swojej aplikacji podczas sprawdzania autoryzacji, aby nie flashować strony logowania za każdym razem, gdy odświeżasz stronę.Następnie przekazujemy flagę na nasze trasy. Tworzymy dwa rodzaje tras
AuthenticatedRoute
iUnauthenticatedRoute
.Do
AuthenticatedRoute.js
wygląda następująco.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}`} />} /> ); }
Sprawdza, czy
isAuthenticated
jest ustawiona natrue
. Jeśli tak, wyrenderuje żądany komponent. Jeśli nie, przekieruje do strony logowania.Z
UnauthenticatedRoute.js
drugiej strony tak wygląda.export default ({ component: C, appProps, ...rest }) => <Route {...rest} render={props => !appProps.isAuthenticated ? <C {...props} {...appProps} /> : <Redirect to="/" />} />;
W tym przypadku, jeśli
isAuthenticated
jest ustawiona nafalse
, wyrenderuje żądany komponent. A jeśli jest ustawiona na true, przekieruje Cię na stronę główną.Szczegółowe wersje tego można znaleźć w naszym przewodniku - https://serverless-stack.com/chapters/create-a-route-that-redirects.html .
Starsza wersja
Zaakceptowana odpowiedź jest prawidłowa, ale Mixins są uważane za szkodliwe ( https://facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html ) przez zespół React.
Jeśli ktoś napotka to pytanie i szuka zalecanego sposobu, aby to zrobić, sugerowałbym użycie komponentów wyższego rzędu zamiast miksów.
Oto przykład HOC, który sprawdza, czy użytkownik jest zalogowany przed kontynuowaniem. A jeśli użytkownik nie jest zalogowany, przekieruje Cię do strony logowania. Ten komponent przyjmuje właściwość o nazwie
isLoggedIn
, która jest w zasadzie flagą, którą aplikacja może przechowywać, aby wskazać, czy użytkownik jest zalogowany.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); }
Aby skorzystać z tego HOC, po prostu owiń go wokół swoich tras. W przypadku twojego przykładu byłoby to:
<Route handler={requireAuth(Todos)} name="todos"/>
Omawiam to i kilka innych tematów w szczegółowym samouczku krok po kroku tutaj - https://serverless-stack.com/chapters/create-a-hoc-that-checks-auth.html
źródło
this.props.isLoggedIn
go natrue
i ominął logowanie?<Route handler={}/>
jest przestarzały w wersji 1.0, powinieneś użyć<Route component={} />
.componentWillMount
wkrótce zostaną wycofane. Przeczytaj to w poście na blogu na stronie internetowej actjs.org . Zamiast tego skorzystam z odpowiedzi podanej przez @jacob.Jest (teraz?) Tego przykład w dokumentacji React Router 4 dla
Redirect
import { Route, Redirect } from 'react-router' <Route exact path="/" render={() => ( loggedIn ? ( <Redirect to="/dashboard"/> ) : ( <PublicHomePage/> ) )}/>
źródło
react-router
zachęca do deklaratywnego podejścia do routera, powinieneś uczynić router tak głupim, jak to tylko możliwe i unikać umieszczania logiki routingu w komponentach.Oto, jak możesz to zrobić (zakładając, że przekażesz to
loggedIn
rekwizyt):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} /> ];
źródło
Jeśli chcesz używać uwierzytelniania w całej aplikacji, musisz przechowywać pewne dane w całej aplikacji (np. Token). Możesz skonfigurować dwa miksy React, które są odpowiedzialne za zarządzanie
$auth
obiektem. Ten obiekt nie powinien być dostępny poza tymi dwoma mikserami. Oto przykład: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(); } } } } }; });
Następnie możesz po prostu
Authenticator
mieszać ze swoimi komponentami logowania (ekran logowania, wyskakujące okienko logowania itp.) I wywoływaćthis.login
funkcję, gdy masz wszystkie niezbędne dane.Najważniejszą rzeczą jest ochrona składników poprzez ich domieszanie
NeedsAuthenticatedUser
. Każdy komponent, który potrzebuje uwierzytelnionego użytkownika, będzie musiał wyglądać tak:var um = require('userManagement'); var ProtectedComponent = React.createClass({ mixins: [um.NeedsAuthenticatedUser] // ... }
Zauważ, że
NeedsAuthenticatedUser
używa funkcji API React-router (willTransitionTo
itransition.abort()
).źródło
Możesz użyć HOC, a auth to zmienna, którą możesz zmienić wartość true lub false oznacza (autoryzacja)
<Route path="/login" component={SignIn} /> <Route path="/posts" render = {() => (auth ? (<Post />) : (<Redirect to="/login" />))}/>
źródło
private-route.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 } }} /> )} />; }
Stosowanie:
<PrivateRoute exact={true} path="/admin/" redirectTo={'/admin/login'} isLogged={this.loginService.isLogged} component={AdminDashboardPage}/> <Route path="/admin/login/" component={AdminLoginPage}/>
Na podstawie https://tylermcginnis.com/react-router-protected-routes-authentication/ .
źródło
zwykle zalogowany użytkownik otrzyma token i używa go do komunikacji z serwerem. To, co zwykle robimy, to definiowanie strony głównej, a rzeczy są tworzone na podstawie tej strony. ta strona główna wykonuje dla Ciebie lokalizację, uwierzytelnianie i inne konfiguracje.
oto przykład
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> );
na swojej stronie głównej sprawdź, czy token nie ma wartości null lub uwierzytelnij token na serwerze, aby sprawdzić, czy użytkownik ma poprawny login.
mam nadzieję że to pomoże :)
źródło