有谁知道如何限制对react-router中特定路由的访问?我想在允许访问特定路由之前检查用户是否已登录。我认为这很简单,但是文档并不清楚如何去做。
这是我应该在我定义<Route>
组件的地方设置的,还是我应该在组件处理程序中处理它?</ p>
<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>
答案 0 :(得分:58)
接受的答案是正确的,但React团队认为Mixins是有害的(https://facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html)。
如果有人遇到这个问题并且正在寻找推荐的方法,我建议使用高阶组件而不是Mixins。
以下是HOC的示例,该HOC将在继续之前检查用户是否已登录。如果用户未登录,则会将您重定向到登录页面。该组件采用名为isLoggedIn
的道具,它基本上是应用程序可以存储的标志,用于表示用户是否已登录。
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);
}
要使用此HOC,只需将其包裹在您的路线周围即可。如果您的示例,它将是:
<Route handler={requireAuth(Todos)} name="todos"/>
我在此处详细介绍了这个以及其他一些主题 - http://serverless-stack.com/chapters/create-a-hoc-that-checks-auth.html
答案 1 :(得分:23)
在React Router 4的Redirect
TemplateSelector
答案 2 :(得分:2)
如果要在整个应用程序中使用身份验证,则需要在应用程序范围内存储一些数据(例如令牌)。您可以设置两个负责管理$auth
对象的React mixin。这个对象不应该在这两个mixin之外可用。这是一个例子:
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();
}
}
}
}
};
});
然后,您可以将Authenticator
混合混合到您的登录组件(登录屏幕,登录弹出窗口等),并在您拥有所需的所有数据时调用this.login
功能。
最重要的是通过混合NeedsAuthenticatedUser
mixin来保护您的组件。需要经过身份验证的用户的每个组件都必须如下所示:
var um = require('userManagement');
var ProtectedComponent = React.createClass({
mixins: [um.NeedsAuthenticatedUser]
// ...
}
请注意,NeedsAuthenticatedUser
使用react-router API(willTransitionTo
和transition.abort()
)。
答案 3 :(得分:1)
react-router
鼓励为您的路由器采用声明式方法,您应该尽可能使路由器变得愚蠢,并避免将路由逻辑放在组件中。
以下是如何做到这一点(假设你将loggedIn
道具传递给它):
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} />
];
答案 4 :(得分:0)
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 }
}} />
)} />;
}
用法:
<PrivateRoute exact={true}
path="/admin/"
redirectTo={'/admin/login'}
isLogged={this.loginService.isLogged}
component={AdminDashboardPage}/>
<Route path="/admin/login/" component={AdminLoginPage}/>
基于https://tylermcginnis.com/react-router-protected-routes-authentication/。
答案 5 :(得分:0)
您可以使用HOC,并且auth是一个变量,您可以更改值true或false表示(授权)
<Route path="/login" component={SignIn} />
<Route path="/posts" render = {() => (auth ? (<Post />) : (<Redirect to="/login" />))}/>
答案 6 :(得分:0)
您可以避免在确认身份验证之前渲染组件,如下所示:
import { useState, useEffect, useRef } from 'react';
import { useHistory } from 'react-router-dom';
const Route = () => {
const [loading, sertLoading] = useState(true);
const history = useHistory();
const ref = useRef<Function>({});
// must use ref!
ref.current.routeGuard = () => {
const authenticationHandler = (): boolean => {
// do authentication here
}
sertLoading(true);
const go = authenticationHandler();
if (go === false) {
history.goBack();
}
sertLoading(false);
}
useEffect(() => {
ref.current.routeGuard();
history.listen(() => {
ref.current.routeGuard();
});
}, []);
return (
<>
{!loading && <YourRouteComponent />}
</>
)
};
或者简单地说,yarn add react-routers
,哪个组件有属性beforeEach
,beforeRoute
,就像Vue Route一样。
答案 7 :(得分:-2)
通常,登录用户将被授予令牌,并使用此令牌与服务器进行任何通信。我们通常做的是定义根页面,并在该页面之上构建。此根页面为您执行本地化,身份验证和其他配置。
这是一个例子
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>
);
在您的根页面上,检查令牌null或使用服务器验证令牌以查看用户是否有效登录。
希望这有助于:)