使用React Router保护React应用中的路由

时间:2020-01-08 20:42:27

标签: reactjs react-router-v4 auth0 react-router-dom

我已经创建了一个简单的React应用,其中包含ReduxReact RouterAuth0,用于处理用户身份验证。

我正在尝试创建此基本行为来控制访问权限:

  • 所有未经身份验证的用户将自动发送到/public
  • 获得授权的用户可以访问应用程序的所有其他部分
  • 一旦用户通过Auth0进行身份验证,我想处理access_token并将用户发送到/组件的Home

一切都“按需”进行。我遇到的问题是render()中的App.jsx函数正在lock.on('authenticated')侦听器之前执行,甚至有机会处理Auth0返回的令牌。结果,令牌永远不会被存储,并且用户似乎总是未经身份验证。如果我将用户发送到/login,则一切正常,因为在呈现Login组件之前,我没有检查用户是否已通过身份验证。

我认为我处理受保护路线的方式需要改变。关于如何处理受保护的路线有什么建议吗?

我在这里提供您需要的代码。如果您想查看整个应用程序,请转到https://github.com/imsam67/react-redux-react-router-auth0-lock

以下是App.jsx

class App extends Component {

    render() {

        const isAuthed = isAuthenticated();

        return (
            <div>
                <Switch>
                    <Route exact path="/" render={ props => isAuthed ? <Home {...props} /> : <Redirect to="/public" /> } />
                    <Route exact path="/login">
                        <Login />
                    </Route>
                    <Route path="/public">
                        <Public />
                    </Route>
                </Switch>
            </div>
        );
    }
}

这是我处理AuthWrapper的{​​{1}}组件:

Auth0

如果您需要查看,这里是class AuthWrapper extends Component { constructor(props) { super(props); this.onAuthenticated = this.onAuthenticated.bind(this); this.lock = new Auth0Lock('my_auth0_client_id', 'my_domain.auth0.com', { auth: { audience: 'https://my_backend_api_url', redirectUrl: 'http://localhost:3000/', responseType: 'token id_token', sso: false } }); this.onAuthenticated(); } onAuthenticated() { debugger; // After successful login, I hit this debugger this.lock.on('authenticated', (authResult) => { debugger; // But I never hit this debugger let expiresAt = JSON.stringify((authResult.expiresIn * 1000) + new Date().getTime()); sessionStorage.setItem('access_token', authResult.accessToken); sessionStorage.setItem('id_token', authResult.idToken); sessionStorage.setItem('expires_at', expiresAt); }); } render() { return( <AuthContext.Provider value={{ lock: this.lock }}> {this.props.children} </AuthContext.Provider> ); } }

index.js

4 个答案:

答案 0 :(得分:0)

这是我为完成这项工作而进行的更改。

  1. 我现在在Auth0 Lock中初始化index.js以使其全局化
  2. 我将onAuthenticated()侦听器移动到LoginCallback.jsx组件,该组件是成功登录后发送用户的地方。我相信将onAuthenticated()App.jsx移到LoginCallback.jsx会产生最大的影响,因为LoginCallback.jsx中的侦听器在App.jsx之前执行。
  3. 在成功进行身份验证时,我还使用this.props.history.push('/');将用户发送到Home组件

有关完整代码,请参见https://github.com/imsam67/react-redux-react-router-auth0-lock上的存储库

答案 1 :(得分:0)

请记住,客户端根本没有任何保护。如果您担心要路由到没有身份验证的组件,只需确保没有暴露任何数据(假设没有令牌就无法获取任何数据),并在路由器检查身份验证或显示错误后将其重定向到该位置。

答案 2 :(得分:0)

请记住,客户端根本没有任何保护。如果您担心要路由到没有身份验证的组件,只需确保没有数据泄露,即使路由器检​​查了身份验证后,如果数据降落到那里也将重定向。我认为@Sam正确。路由可能不会像预期的那样对更改它的异步调用做出响应,或者行为可能很奇怪。我从来没有尝试过这种动态路由,但是总是有条件地渲染内容组件。更好的方法可能是发送呼叫,然后在然后阻止重定向到路由器知道要处理的URL。只是不确定路由器是否可以很好地处理。捕获组件,以在加载时检查auth,如果未授权,则重定向回登录。抱歉,我在这里没有提供任何帮助,但是条件路由似乎似乎是一种反模式,但是我想如果我们知道路由器在更改后如何呈现其数据或实际上是否能够执行(路由自己),它就可以工作。他们将这个网址加为书签,然后尝试返回404,对吗?也许像401未经授权的显示和重定向或登录链接可能更好?

答案 3 :(得分:-1)

动态路由需要在<Switch>范围之外定义。这是一个示例,假设您的函数isAuthenticated()是一种状态(Redux或Wathever)

import React from "react";
import ReactDOM from "react-dom";
import { createBrowserHistory } from "history";
import { Router, Route, Switch, Redirect } from "react-router-dom";

// core components
import Admin from "layouts/Admin.js";
import SignIn from "layouts/SignIn";

const hist = createBrowserHistory();
const loggedRoutes = () => (
  <Switch>
    <Route path="/" component={SignIn} />
    <Route path="/admin" component={Admin} />
    <Redirect from="/admin" to="/admin/aboutUs/whatWeDo" />
  </Switch>
);
const routes = () => (
  <Switch>
    <Route path="/" component={SignIn} />
    <Route path="/login" component={Admin} />
    <Redirect from="/" to="/login" />
  </Switch>
);
ReactDOM.render(
  <Router history={hist}>
    {checkIfAuth? loggedRoutes():routes()}
  </Router>,
  document.getElementById("root")
);

在此示例中,如果您未登录,则将重定向到/ login。