2016-12-19 4 views
2

私はReactアプリケーションにAuth0認証を追加しようと努めていますが、それが機能しているにもかかわらず、これにアプローチするより良い方法があるように感じます。私は認証ロジックのためのより良いパターンを理解するために苦労しています。認証されたReactコンポーネントとルートのより良いパターン

アプリの設定はreact + redux + react-router-redux + redux-saga + + auth0-lockimmutableです。上から順に

Appコンポーネントは両方BuilderEditorコンポーネントはログインするユーザーを要求し、認証の処理を担当高次コンポーネントでauthenticated()ラップそれぞれ、基本的なページレイアウトを定義します。現時点で

// index.js 

import App from './containers/App'; 
import Builder from './containers/Builder'; 
import Editor from './containers/Editor'; 
import Home from './containers/Home'; 
import Login from './containers/Login'; 

import AuthContainer from './containers/Auth0/AuthContainer'; 

... 

ReactDOM.render(
    <Provider store={reduxStore}> 
    <Router history={syncedHistory}> 
     <Route path={'/'} component={App}> 
     <IndexRoute component={Home} /> 
     <Route path={'login'} component={Login} /> 
     <Route component={AuthContainer}> 
      <Route path={'builder'} component={Builder} /> 
      <Route path={'editor'} component={Editor} /> 
     </Route> 
     </Route> 
     <Redirect from={'*'} to={'/'} /> 
    </Router> 
    </Provider>, 
    document.getElementById('app') 
); 

AuthContainerisLoggedInためReduxのストアをチェック除いてあまりしません。 isLoggedInがfalseの場合、ユーザーはコンポーネントを表示することができず、/loginにリダイレクトされます。

// containers/Auth0/AuthContainer.js 

import React from 'react'; 
import { connect } from 'react-redux'; 
import { bindActionCreators } from 'redux'; 

import { redirectToLogin } from './Auth0Actions'; 

class AuthContainer extends React.Component { 
    componentWillMount() { 
    if (!this.props.isLoggedIn) { 
     this.props.actions.redirectToLogin(); 
    } 
    } 
    render() { 
    if (!this.props.isLoggedIn) { 
     return null; 
    } 
    return this.props.children; 
    } 
} 

// mapStateToProps(), mapDispatchToProps() 

export default connect(mapStateToProps, mapDispatchToProps)(AuthContainer); 

次の部分はAuth0です。 Auth0ロックは「リダイレクト」モードで動作します。つまり、ユーザーはアプリをログインしたままにしてから/loginにアプリにリダイレクトされます。リダイレクトの一環として、Auth0はURLの一部としてトークンを添付します。このトークンは、アプリケーションの読み込み時に解析する必要があります。

const lock = new Auth0Lock(__AUTH0_CLIENT_ID__, __AUTH0_DOMAIN__, { 
    auth: { 
    redirect: true, 
    redirectUrl: `${window.location.origin}/login`, 
    responseType: 'token' 
    } 
}); 

Auth0が/loginにリダイレクトするので、Loginコンポーネントは、認証ロジックを必要とします。 AuthContainerと同様に、還元店でisLoggedInを確認します。 isLoggedInが真の場合、ルート/にリダイレクトされます。 isLoggedInがfalseの場合、認証を試みます。

// containers/Login/index.js 

import React from 'react'; 
import { connect } from 'react-redux'; 
import { bindActionCreators } from 'redux'; 

import { authenticate, redirectToRoot } from '../Auth0/Auth0Actions'; 

class Login extends React.Component { 
    componentDidMount() { 
    if (!this.props.isLoggedIn) { 
     this.props.actions.authenticate(); 
    } 
    else { 
     this.props.actions.redirectToRoot(); 
    } 
    } 
    render() { 
    return (
     <div>Login Page</div> 
    ); 
    } 
} 

// mapStateToProps(), mapDispatchToProps() 

export default connect(mapStateToProps, mapDispatchToProps)(Login); 

これらの部分を配置すると、Auth0との統合が機能しているようです。しかし、今私はAuthContainerLoginコンポーネントを持っていて、それらは非常に似ています。ログインページが実際にログインするユーザーを必要としないので、私は理想的には、すべての認証ロジックが一つの場所に住んでいます。AuthContainerの子として

Loginコンポーネントを配置することはできませんが、私は把握するのに苦労しています特にAuth0リダイレクトの特殊なケースでは、それを動作させる別の方法です。私は助けることはできませんが、別のアプローチ、反応+ reduxアプリで認証フローのためのより良いパターンがあると考える必要があります。

便利なことは、アプリケーションが初期化を開始する前に、ページの読み込みに非同期アクションをディスパッチする方法を理解することです。 Auth0はコールバックで動作するので、Auth0が登録されたコールバックを呼び出すまで、redux初期状態の設定を遅らせる必要があります。ページ読み込み時に非同期アクションを処理するための推奨される方法は何ですか?


私はアクションとサガのように、簡潔にするためにいくつかの作品を残してきたが、それが参考になるだろう場合、私はそれらを提供するために幸せを超えるだろう。

答えて

1

私は以下の私のコードを見て、私のプロジェクトで同じことをやってreduxで細かい作業、react-routerだ:

ルート

export default (
    <div> 
    <Route path="/" component={AuthenticatedComponent}> 
    <Route path="user" component={User} /> 
    <Route path="user/:id" component={UserDetail} /> 
    </Route>  
    <Route path="/" component={notAuthenticatedComponent}> 
    <Route path="register" component={RegisterView} /> 
    <Route path="login" component={LoginView} /> 
    </Route>  
    </div> 
); 

AuthenticatedComponent

export class AuthenticatedComponent extends React.Component { 
     constructor(props) { 
     super(props); 
     } 

     componentWillMount() { 
     this.props.checkAuth().then(data => { 
      if (data) { 
      this.props.loginUserSuccess(data); 
      } else { 
      browserHistory.push('/login'); 
      } 
     }); 
     } 

     render() { 
     return (
     <div> 
      { this.props.isAuthenticated && <div> { this.props.children } </div> } 
     </div> 
     ); 
     } 
    } 

notAuthenticatedComponent

export class notAuthenticatedComponent extends React.Component { 
    constructor(props){ 
    super(props);  
    } 

    componentWillMount(){ 
    this.props.checkAuth().then((data) => { 
     if(data && (this.props.location.pathname == 'login')){ 
     browserHistory.push('/home'); 
     } 
    }); 
    } 

    render(){ 
    return (
     <div> 
     { this.props.children } 
     </div> 
    ); 
    } 
} 
+0

にあなたの最初の呼び出しの前にこれを行うことができますか?私はこれを昨日見つけました。https://github.com/facebook/react/issues/7671 – Hristo

1

は、そのためにとても残念完全な答えではない可能性があります。いくつかの事はここに対処する:

理想的には、すべての認証ロジックは、一つの場所

に住んでいる私は、これはあなたが「1位」によって何を意味するかに応じて、理想的であるので、よく分かりません。似ているが、いくつかの面では少し違った機能を持つことに間違いがあります。私はあなたのコードを見ることができるので、ロジックは実際にわずかに異なるので、2つのコンポーネントは完全にうまくいくようです。部品実装後に認証ロジックを置く

代わりのcomponentDidMount

は、ルートのonEnter小道具使用

おそらく実行することができます認証ロジック前に認証済みのhtml示すのちらつきの原因となります。概念的には、authロジックが実行されるまで、このコンポーネントのレンダリングが行われないようにしたいとします。 RouteのonEnterはこれに最適です。アプリは

この初期化を開始する前に、ページのロード時に非同期アクションをディスパッチする方法https://github.com/ReactTraining/react-router/blob/master/docs/API.md#onenternextstate-replace-callback

let authenticate = (nextState, replace) => { 
    // check store details here, if not logged in, redirect 
} 

<Route path={'builder'} onEnter={authenticate} component={Builder} /> 

アプリ/のSPAを反応させるのための非常に一般的な質問です。私は可能な限り最高のユーザーエクスペリエンスは、すぐに何かを表示すること、おそらくローディングスピナー、または「ユーザーの詳細を取得する」などの何かを表示することだと思います。あなたは、トップレベルのApp容器に、あるいは `componentWillMount()`使用しての背後にある動機何ReactDOM.render

ReactDOM.render(<SplashLoader />, element) 

authCall().then(data => 
    ReactDOM.render(<App data={data} />, element) 
).catch(err => 
    ReactDOM.render(<Login />, element) 
} 
+0

私の最初の試みは 'onEnter'を使っていましたが、私はそれを動作させることができませんでした。また、私は 'https://github.com/mjrussell/redux-auth-wrapper#motivation – Hristo

+0

を読んだ後、' onEnter'を使用することをお勧めしませんでした。ベストプラクティスが何であるか、最善のアプローチが何であるか分かりません。私は、高次コンポーネントを使用して、正規のコンポーネントをラウンドして、認証専用のレイヤーを使用する考えが好きです。概念的には、それは抽象として多くの意味を持ちますが、onEnterは素早く修正されているようです。 – Hristo

+0

確かにそれは良いアプローチだと思いますが、あなたの例ではコンポーネントをレンダリングしています。私はおそらくHOCの代わりに、@ Nguyenの例 – azium

関連する問題