受保护路由上的Firebase authState

时间:2018-03-10 14:36:32

标签: javascript reactjs

如果用户未登录firebase,我试图在登录页面上重定向。我已经完成了检查用户状态的PrivateRoute,如果没有记录,则会重定向。 问题: 当我输入登录信息时,它不会做任何事情。如果我再次放,那么我将重定向到受保护的主页。看起来状态在第一次登录后不会刷新,但是在第二次登录时它是。

登录组件:

getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);

路由的app.js:

import React, {Component} from 'react';
import Wrapper from '../../../utils/Wrapper';
import * as authFunctions from '../../../Functions/Auth';
import * as constants from "../../../utils/Constants";
import * as errorsFirebase from "../../../utils/FirebaseErrors";
import globalCss from "../../Style/Global.css";
import css from "../Signin/Signin.css";
import { Link } from 'react-router-dom'
import {  Row, Col } from 'react-flexbox-grid';
import * as localization from '../../../Localization';
import Input from '../../Input/Input';
import LoginContainer from '../LoginContainer'

class Signin extends Component{
    constructor(args){
        super(args);
        this.state = {
            user:null,
            auth: {}
        }
    }

    loginSuccess = (user)=>{
        //redirect to home:
        this.props.history.push(constants.HOME);
    }

    loginError = (error) =>{
        const tempState = JSON.parse(JSON.stringify(this.state));
        switch(error.code){
            case errorsFirebase.LOGIN_BAD_FORMAT_EMAIL:
                tempState.auth.error = localization.stringsSignin.ERROR_INVALID_EMAIL;
                tempState.auth.errorEmail = true;
                break;
            case errorsFirebase.LOGIN_INVALID_PASSWORD:
                tempState.auth.error = localization.stringsSignin.ERROR_INVALID_PASSWORD;
                tempState.auth.errorPassword = true;
                break;
            case errorsFirebase.LOGIN_USER_NOT_FOUND:
                tempState.auth.error = localization.stringsSignin.ERROR_USER_NOT_FOUND;
                tempState.auth.errorLogin = true;
                break;
            default:
                tempState.auth.error = localization.stringsSignin.ERROR_INVALID_PASSWORD;
                break;
        }
        this.setState(tempState);
    }

    loginHandler = (email,psw) =>{
        authFunctions.login(email,psw,this.loginSuccess, this.loginError);
    };

    onInputChange = (e) =>{
        const tempState = JSON.parse(JSON.stringify(this.state));
        if(e.target.id === "email")
            tempState.auth.email = e.target.value;
        if(e.target.id === "psw")
            tempState.auth.psw = e.target.value;

        tempState.auth.error = null;
        tempState.auth.errorLogin = false;
        tempState.auth.errorPassword = false;
        tempState.auth.errorEmail = false;
        this.setState(tempState);
    }

    render() {
        const hasErrorEmail = this.state.auth.errorEmail?this.state.auth.errorEmail:false;
        const hasErrorPassword = this.state.auth.errorPassword?this.state.auth.errorPassword:false;
        const hasErrorLogin = this.state.auth.errorLogin?this.state.auth.errorLogin:false;
        const error = this.state.auth.error ? this.state.auth.error:"";
        return (
            <Wrapper>
                <LoginContainer>
                    <Row className="margin-top-30">
                        <Col xs={10}>
                            <p className="Right-title"> {localization.stringsSignin.RIGHT_TITLE} </p>
                        </Col>
                    </Row>
                    <Row>
                        <Col xs={10} className="White-Base">
                            <Input xs={12}
                                   label={localization.stringsSignin.LABEL_USERNAME}
                                   inputId="email"
                                   inputType="email"
                                   hasError={hasErrorEmail || hasErrorLogin}
                                   change={this.onInputChange.bind(this)}/>
                            <Input xs={12}
                                   label={localization.stringsSignin.LABEL_PASSWORD}
                                   inputId="psw"
                                   inputType="password"
                                   hasError={hasErrorPassword || hasErrorLogin}
                                   change={this.onInputChange.bind(this)}/>
                            <Col xs={12}>&nbsp;</Col>
                            <Col xs={12}>
                                <p className="error">{error}</p>
                            </Col>
                        </Col>
                    </Row>
                    <Row>
                        <Col xs={12} className="button-container">
                            <button className="btn-dark btn-sign" onClick={this.loginHandler.bind(this,this.state.auth.email,this.state.auth.psw)}>Sign In</button>
                            <Link className="forgot-Password" to={constants.FORGOT}>Forgot Password?</Link>
                        </Col>
                    </Row>
                </LoginContainer>
            </Wrapper>
        )
    }
}

export default Signin;;

PrivateRoute:

import React, { Component } from 'react';
import Wrapper from '../src/utils/Wrapper';
import Signin from '../src/components/Login/Signin/Signin';
import Signout from '../src/components/Login/Signout/Signout';
import Forgot from '../src/components/Login/Forgot/Forgot';
import ChangePassword from '../src/components/Login/ChangePassword/ChangePassword';
import UserActivity from '../src/components/Home/UserActivity/UserActivity'
import ManageQuizzes from '../src/components/Home/ManageQuizzes/ManageQuizzes'
import ManageProducts from '../src/components/Home/ManageProducts/ManageProducts'
import {BrowserRouter, Route, Switch} from 'react-router-dom';
import firebase from 'firebase'
import * as constants from "./utils/Constants";
import PrivateRoute from './components/Route/PrivateRoute/PrivateRoute';
import PageNotFound from './components/PageNotFound/PageNotFound';
import {FirebaseAuth} from "./utils/Firebase";

class App extends Component {
    constructor(args){
        super(args);
        this.state = {
            authUser:null,
            isLoading:true
        }
    }

    authUser = () => {
        return new Promise((resolve, reject) => {
            firebase.auth().onAuthStateChanged((user) => {
                this.setState({isLoading:false});
                if (user) {
                    resolve(user);
                } else {
                    reject("not logged")
                }
            });
        });
    }

    componentDidMount() {
        this.authUser().then((user) => {
            this.setState({ authUser: user });
        }, ((e)=>{
            this.setState({ authUser: null });
        }));
    }

    render() {
        if (this.state.isLoading) return null;
        return (
            <BrowserRouter>
                <Wrapper>
                    <Switch>
                        <PrivateRoute path={constants.HOME}  exact component={UserActivity} authUser={this.state.authUser}/>
                        <PrivateRoute path={constants.MANAGE_QUIZZES}  exact component={ManageQuizzes}/>}/>
                        <PrivateRoute path={constants.MANAGE_PRODUCTS} exact component={ManageProducts}/>}/>

                        <Route path={constants.SIGNIN} exact component={Signin}/>
                        <Route path={constants.FORGOT} exact component={Forgot}/>
                        <Route path={constants.CHANGE_PASSWORD} exact component={ChangePassword}/>
                        <Route path={constants.SIGNOUT} exact component={Signout}/>}/>

                        /*Last component MUST the 404*/
                        <Route component={PageNotFound}/>
                    </Switch>
                </Wrapper>
            </BrowserRouter>
        );
    }
}
export default App;

我更喜欢不使用redux。

由于

1 个答案:

答案 0 :(得分:0)

我终于找到了解决方案。对于我所知道的问题是在路由过程中并为了解决它我已经为保存登录信息添加了一个redux-store。所以:

在signin组件中,当我调用firebase进行登录时,它将在成功登录时在商店中设置记录:

import React, {Component} from 'react';
import Wrapper from '../../../utils/Wrapper';
import * as authFunctions from '../../../Functions/Auth';
import * as constants from "../../../utils/Constants";
import * as errorsFirebase from "../../../utils/FirebaseErrors";
import globalCss from "../../Style/Global.css";
import css from "../Signin/Signin.css";
import { Link } from 'react-router-dom'
import {  Row, Col } from 'react-flexbox-grid';
import * as localization from '../../../Localization';
import Input from '../../Input/Input';
import LoginContainer from '../LoginContainer'
import AdminUser from '../../../hoc/AdminUser/AdminUser';
import {connect} from 'react-redux'

class Signin extends Component{
    constructor(args){
        super(args);
        this.state = {
            errorLogin:null,
            auth: {}
        }
    }

    loginSuccess = (user)=>{
        const adminUser =  AdminUser.getInstance(user);
        this.props.onAdminLoggedIn(adminUser);
        this.props.history.push(constants.HOME);
    }

    loginError = (error) =>{
        const tempState = JSON.parse(JSON.stringify(this.state));
        switch(error.code){
            case errorsFirebase.LOGIN_BAD_FORMAT_EMAIL:
                tempState.auth.error = localization.stringsSignin.ERROR_INVALID_EMAIL;
                tempState.auth.errorEmail = true;
                break;
            case errorsFirebase.LOGIN_INVALID_PASSWORD:
                tempState.auth.error = localization.stringsSignin.ERROR_INVALID_PASSWORD;
                tempState.auth.errorPassword = true;
                break;
            case errorsFirebase.LOGIN_USER_NOT_FOUND:
                tempState.auth.error = localization.stringsSignin.ERROR_USER_NOT_FOUND;
                tempState.auth.errorLogin = true;
                break;
            default:
                tempState.auth.error = localization.stringsSignin.ERROR_INVALID_PASSWORD;
                break;
        }
        this.setState(tempState);
    }

    loginHandler = (email,psw) =>{
        if(this.state.errorLogin === null)  authFunctions.login(email,psw,this.loginSuccess, this.loginError);
    };

    onInputChange = (e) =>{
        const tempState = JSON.parse(JSON.stringify(this.state));
        if(e.target.id === "email")
            tempState.auth.email = e.target.value;
        if(e.target.id === "psw")
            tempState.auth.psw = e.target.value;

        tempState.auth.error = null;
        tempState.auth.errorLogin = false;
        tempState.auth.errorPassword = false;
        tempState.auth.errorEmail = false;
        this.setState(tempState);
    }

    render() {
        const hasErrorEmail = this.state.auth.errorEmail?this.state.auth.errorEmail:false;
        const hasErrorPassword = this.state.auth.errorPassword?this.state.auth.errorPassword:false;
        const hasErrorLogin = this.state.auth.errorLogin?this.state.auth.errorLogin:false;
        const error = this.state.auth.error ? this.state.auth.error:"";
        return (
            <Wrapper>
                <LoginContainer>
                    <Row className="margin-top-30">
                        <Col xs={10}>
                            <p className="Right-title"> {localization.stringsSignin.RIGHT_TITLE} </p>
                        </Col>
                    </Row>
                    <Row>
                        <Col xs={10} className="White-Base">
                            <Input xs={12}
                                   label={localization.stringsSignin.LABEL_USERNAME}
                                   inputId="email"
                                   inputType="email"
                                   hasError={hasErrorEmail || hasErrorLogin}
                                   change={this.onInputChange.bind(this)}/>
                            <Input xs={12}
                                   label={localization.stringsSignin.LABEL_PASSWORD}
                                   inputId="psw"
                                   inputType="password"
                                   hasError={hasErrorPassword || hasErrorLogin}
                                   change={this.onInputChange.bind(this)}/>
                            <Col xs={12}>&nbsp;</Col>
                            <Col xs={12}>
                                <p className="error">{error}</p>
                            </Col>
                        </Col>
                    </Row>
                    <Row>
                        <Col xs={12} className="button-container">
                            <button className="btn-dark btn-sign" onClick={this.loginHandler.bind(this,this.state.auth.email,this.state.auth.psw)}>Sign In</button>
                            <Link className="forgot-Password" to={constants.FORGOT}>Forgot Password?</Link>
                        </Col>
                    </Row>
                </LoginContainer>
            </Wrapper>
        )
    }
}

const mapStateToProps = state =>{
    return {
        ctr: state
    }
}

const mapDispatchToProps = dispatch =>{
    return {
        onAdminLoggedIn : (user) =>{
            dispatch({type: constants.REDUX_PUT_USER_STATE,payload:user})
        },
    }
}

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

浏览器路由器会将存储用户的信息传递给受保护的路由器:

import React, { Component } from 'react';
import Wrapper from '../src/utils/Wrapper';
import Signin from '../src/components/Login/Signin/Signin';
import Signup from '../src/components/Login/Signup/Signup';
import Signout from '../src/components/Login/Signout/Signout';
import Forgot from '../src/components/Login/Forgot/Forgot';
import ChangePassword from '../src/components/Login/ChangePassword/ChangePassword';
import UserActivity from '../src/components/Home/UserActivity/UserActivity'
import ManageQuizzes from '../src/components/Home/ManageQuizzes/ManageQuizzes'
import ManageProducts from '../src/components/Home/ManageProducts/ManageProducts'
import {BrowserRouter, Route, Switch} from 'react-router-dom';
import firebase from 'firebase'
import * as constants from "./utils/Constants";
import PrivateRoute from './components/Route/PrivateRoute/PrivateRoute';
import PageNotFound from './components/PageNotFound/PageNotFound';
import {FirebaseAuth} from "./utils/Firebase";
import {connect} from 'react-redux'
import AdminUser from './hoc/AdminUser/AdminUser';


class App extends Component {
    constructor(args){
        super(args);
        this.state = {
        }
    }

    componentDidMount(){
        firebase.auth().onAuthStateChanged((user) => {
            const adminUser =  AdminUser.getInstance(user);
            this.props.onAdminLoggedIn(adminUser);
        })
    }

    render() {
        if(this.props.ctr.user === null) return null;
        return (
            <BrowserRouter>
                <Wrapper>
                    <Switch>
                        <PrivateRoute path={constants.HOME}  exact component={UserActivity} authUser={this.props.ctr.user} />
                        <PrivateRoute path={constants.MANAGE_QUIZZES}  exact component={ManageQuizzes} authUser={this.props.ctr.user}/>
                        <PrivateRoute path={constants.MANAGE_PRODUCTS} exact component={ManageProducts} authUser={this.props.ctr.user}/>}/>
                        /*Admin users can only sign up for testing*/
                        <PrivateRoute path={constants.SIGNUP}  exact component={Signup} authUser/>
                        /*-----*/
                        <Route path={constants.SIGNIN} exact component={Signin}/>
                        <Route path={constants.FORGOT} exact component={Forgot}/>
                        <Route path={constants.CHANGE_PASSWORD} exact component={ChangePassword}/>
                        <Route path={constants.SIGNOUT} exact component={Signout}/>}/>



                        /*Last component MUST the 404*/
                        <Route component={PageNotFound}/>
                    </Switch>
                </Wrapper>
            </BrowserRouter>
        );
    }
}

const mapStateToProps = state =>{
    return {
        ctr: state
    }
}

const mapDispatchToProps = dispatch =>{
    return {
        onAdminLoggedIn : (user) =>{
            dispatch({type: constants.REDUX_PUT_USER_STATE,payload:user})
        },
    }
}

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

最后是管理重定向的私有路由器:

import React from 'react';
import { Redirect, Route } from 'react-router-dom'
import * as constants from '../../../utils/Constants'
import firebase from 'firebase';

const PrivateRoute = ({component: Component, authUser, ...rest}) => {
    return (
        <Route
                {...rest}
                render={(props) => (authUser?true:false)
        ? <Component {...props} />
        : <Redirect to={{pathname: constants.SIGNIN, state: {from: props.location}}} />}
            />

    )
}

export default PrivateRoute

总之,如果不使用redux商店,我找不到解决方案。这是因为(imo)场景中有太多变量:

  • firebase asyncing,
  • 来自登录的更改页面
  • PrivetRoute的更改页面
  • 路由