【问题标题】:Redux and Token Authentication : how to redirect the userRedux 和令牌认证:如何重定向用户
【发布时间】:2020-02-26 06:59:18
【问题描述】:

我制作了自己的 Django REST 框架 API,并包含了令牌身份验证。一切正常,我可以获得令牌和东西,但是,我在重定向我的用户时遇到了一些麻烦,使用:

this.props.push('/');

这是 UI 身份验证背后的逻辑:

import React, {Component} from 'react';
import { connect } from 'react-redux';
import {authLogin} from '../../actions/authentication.js';

class Login extends Component {

  constructor(props){
    super(props);
    this.state = {
      email: "",
      password: ""
    }
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(e){
    this.setState({[e.target.name]: e.target.value});
  }

  handleSubmit(e){
    e.preventDefault();
    this.props.authLogin(this.state.email, this.state.password);
    console.log(this.props.isAuthenticated);
    console.log(this.props.loading);
      if (this.props.isAuthenticated){
        this.props.history.push('/');
    }
  }

  render(){
    return(
      <div className="Login">
        <h1> This is a form </h1>
        <form>
          <input type="text" onChange={this.handleChange} name="email"/>
          <input type="password" onChange={this.handleChange} name="password"/>
          <input type="submit" onClick={this.handleSubmit}/>
          { this.props.isAuthenticated &&
            <p>Hello </p>
          }
        </form>
      </div>
    )
  }
}

const mapStateToProps = state => {
  console.log(state);
  return {
    token: state.authentication.token
  }
}

export default connect(mapStateToProps, {authLogin})(Login);

这个登录组件在一个容器组件中,这是我希望我的 Redux 告诉“嘿,这是新令牌”的地方:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import {connect } from 'react-redux';
import AppHeader from './header/AppHeader';
import HomePageStream from './HomePageStream/HomePageStream.js';
import HeaderCategories from './header/HeaderCategories.js';
import ArticleDetails from './ArticleDetails/ArticleDetails.js';
import { Route, Switch } from 'react-router-dom';
import { transitions, positions, Provider as AlertProvider } from 'react-alert'
import AlertTemplate from 'react-alert-template-basic'
import Alerts from './Alerts/Alerts.js';
import {authStateCheck} from '../actions/authentication.js';
import { Provider } from 'react-redux'
import { store } from '../store.js';
import { BrowserRouter } from "react-router-dom";
import Login from './Authentication/Login.js';


const options = {
  timeout: 2000,
  position: "top center"
}


class Container extends Component {

  componentDidMount(){
    this.props.authStateCheck();
  }

  render(){
    return(
      <div className="Container">
        <Provider store={store}>
            <AlertProvider template={AlertTemplate}
                           {...options}
            >
            <AppHeader />
            <Alerts />
            <HeaderCategories />
            <Switch>
                <Route exact
                       path="/:category"
                       render={routerProps => <HomePageStream {...routerProps}/>}
                />
                <Route exact
                       path="/article/:slug"
                       render={routerProps => <ArticleDetails {...routerProps}/>}
                />
                <Route exact
                       path="/authentication/login"
                       render={ routerProps => <Login {...routerProps}{...this.props}/>}
                />
            </Switch>
            </AlertProvider>
        </Provider >
      </div>
    )
  }
}

const mapStateToProps = state => {
  console.log(state.authentication);
  return {
    isAuthenticated: state.authentication.token !== null,
    loading: state.authentication.loading
  }
}

export default connect(mapStateToProps, {authStateCheck} )(Container);

这是问题: 当我点击提交时,isAuthenticated 是假的,因为我只在调用 handleSubmit() 之后才获得令牌!

这是我的操作代码:

import axios from 'axios';
import {AUTH_START, AUTH_FAIL, AUTH_SUCESS, AUTH_LOGOUT} from './type';


export const authStart = () => {
  return {
    type: AUTH_START,
    loading: true
  };
}

export const authSucess = token => {
  console.log(token);
  return {
    type: AUTH_SUCESS,
    token: token,
    error: null,
    loading: false
  };
}

export const authFail = error => {
  console.log(error)
  return {
    token: null,
    type: AUTH_FAIL,
    error: error,
    loading: false
  };
}


export const logout = () => {
  window.localStorage.removeItem('token');
  window.localStorage.removeItem('expiration_time');
  return {
    type: AUTH_LOGOUT
  }
}


export const checkAuthTimeOut = expiration_time => dispatch => {
  return setTimeout(()=> {
    dispatch(logout());
  }, expiration_time * 1000);
}



export const authLogin = (email, password) => dispatch => {
  dispatch(authStart());
  console.log("I'm authlogin ! ");
  axios.post('http://127.0.0.1:8000/rest-auth/login/',{
      "email": email,
      "password": password
  })
  .then( res => {
    console.log("RESPONSE !")
    const token = res.data.key
    const expiration_time = new Date(new Date().getTime() + 3600 * 1000);
    window.localStorage.setItem('token', token);
    window.localStorage.setItem('expiration_time', expiration_time);
    dispatch(authSucess(token));
    console.log(token);
    dispatch(checkAuthTimeOut(3600));
  })
  .catch( err => {
    console.log(err);
    dispatch(authFail());
  })
}


export const authStateCheck = () => dispatch => {
  const expiration_time = window.localStorage.getItem('expiration_time');
  const token = window.localStorage.getItem('token');
  if (!token){
    return dispatch(logout());
  } else if ( expiration_time <= new Date()){
    console.log("EXPIRATION");
    console.log( expiration_time <= new Date() )
    return dispatch(logout());
  } else {
    console.log("NEW TIMER !!!! ");
    return checkAuthTimeOut((expiration_time - new Date().getTime()) / 1000)
  }
}

这是我的减速器:

import {AUTH_START, AUTH_FAIL, AUTH_SUCESS, AUTH_LOGOUT} from '../../actions/type';


const initialState = {
  error: null,
  token: null,
  loading: false
}

export function authenticationReducer(state = initialState, action){
  switch (action.type) {
    case AUTH_START:
      return {
        ...state,
        loading: true
      }
    case AUTH_SUCESS:
      console.log(action.token);
      console.log(action.loading);
      return {
        ...state,
        error: null,
        token: action.token,
        loading: false
      }

    case AUTH_FAIL:
      return {
        ...state,
        error: action.error
      }
    default:
      return state

  }
}

但是,如果我再点击一次提交,它就会起作用。但我真的希望我的用户立即被重定向。我怎样才能解决这个问题 ??

B 非常感谢;(

【问题讨论】:

  • github.com/supasate/connected-react-router,允许您在成功或失败的操作中调度推送、弹出等历史方法。因此在 authLogin 中,您将触发 history.push("/") 以重定向成功的 api 调用。

标签: javascript reactjs redux jwt


【解决方案1】:

我建议删除 history.push 代码并让 react-router 处理重定向:

import { Route, Redirect } from 'react-router'
...
<Switch>
                    <Route exact
                           path="/:category"
                           render={routerProps => <HomePageStream {...routerProps}/>}
                    />
                    <Route exact
                           path="/article/:slug"
                           render={routerProps => <ArticleDetails {...routerProps}/>}
                    />
                    <Route exact
                           path="/authentication/login"
                           render={ routerProps => (this.props.isAuthenticated ? (<Redirect to="/"/>) :(<Login {...routerProps}{...this.props}/>))}
                    />
</Switch>

【讨论】:

  • 这太完美了!谢谢 !只是一个关于用户体验的快速问题。既然他已通过身份验证并拥有令牌,那么他访问个人资料页面的最佳方式是什么?我是否必须执行 GET 请求才能根据令牌获取此特定用户?有没有更好的解决方案?
  • 除了敏感信息之外,您还可以将其包含在令牌配置文件信息中,否则您需要为此类信息添加 api。
猜你喜欢
  • 2023-04-03
  • 2013-10-14
  • 1970-01-01
  • 1970-01-01
  • 2019-07-31
  • 1970-01-01
  • 2017-06-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多