react通过react-router-dom拦截实现登录验证

在使用react开发项目中,有些页面需要登录之后才能访问,所以需要进行拦截,此处分享采用react-router-dom v4+redux+redux-saga+ant-mobile+axios技术来实现

Login.jsx

import React from "react";
import { is, fromJS } from "immutable";
import { connect } from "react-redux";
import { PropTypes } from "prop-types";
import { login } from "../../store/login/action";
import { InputItem, Button, List } from "antd-mobile";

class Login extends React.Component {
  static propTypes = {
    loginInfo: PropTypes.object.isRequired,
    login: PropTypes.func.isRequired
  };
  constructor(props) {
    super(props);
    this.state = { name: "", psd: "" };
  }
  //antd-mobile的InputItem必须用List组件包裹,其输入值就是value
  username = value => {
    this.setState({
      name: value
    });
  };
  password = value => {
    this.setState({
      psd: value
    });
  };
  toLogin = () => {
    if (this.state.name === "") {    
        // to do sth
    } else if (this.state.psd === "") {
      // to do sth
    } else {
      let data = {};
      data.username = this.state.name;
      data.password = this.state.psd;
    // 触发action
      this.props.login(data);
    }
  };
  componentWillReceiveProps(nextProps) {
      if (Object.keys(nextProps.loginInfo).length > 0) {
        if (nextProps.loginInfo.result.code === 10000) {
          // 登录成功
          sessionStorage.setItem(
            "userinfo",
            JSON.stringify(nextProps.loginInfo.data[0])
          );
          setTimeout(() => {
            let RedirectUrl = nextProps.location.state
              ? nextProps.location.state.from.pathname
              : "/";
            nextProps.history.push(RedirectUrl);
          }, 200);
        } else {

        }
      }
  }
  shouldComponentUpdate(nextProps, nextState) {
    return (
      !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
    );
  }
  componentWillUpdate(nextProps, nextState) {}
  componentWillMount() {}
  render() {
    return (
      
); } componentDidMount() {} componentDidUpdate() {} componentWillUnmount() {} } export default connect( state => ({ loginInfo: state.loginInfo.userinfo }), { login } )(Login);

utils/asyncCompontent.jsx

import React from 'react'
export default function asyncComponent(importComponent){
    class AsyncComponent extends React.Component{
        constructor(props){
            super(props);
            this.state = {
                component:null
            };
        }
        async componentDidMount(){
            const {default:component} = await importComponent();
            this.setState({component});
        }
        render(){
            const C = this.state.component;
            return C ?  : null;
        }
    }
    return AsyncComponent;
}

router/index.js

import React from "react";
import { HashRouter, Route, Redirect, Switch } from "react-router-dom";
import { PrivateRoute } from "./auth"; //需要登录的路由
import asyncComponent from "../utils/asyncComponent";//按需加载
import app from "../App";
const example = asyncComponent(() =>import("../components/antiDesign/example"));
const login = asyncComponent(() => import("../components/login/login"));
const noMatch = asyncComponent(() => import("../components/noMatch/noMatch"));

class RouteConfig extends React.Component {
  render() {
    return (
      
        
          
          
          
          
        
      
    );
  }
}

export default RouteConfig;

router/auth.js

import React, { Component } from "react";
import { connect } from "react-redux";
import { Route, Redirect } from "react-router-dom";

export const PrivateRoute = ({ component: ComposedComponent, ...rest }) => {
  class Authentication extends Component {
    render() {
      let isLogin= this.props.isLogin
        ? this.props.isLogin
        : sessionStorage.getItem("userinfo")
          ? sessionStorage.getItem("userinfo")
          : "";
      return (
        
            !isLogin? (
              
            ) : (
              
            )
          }
        />
      );
    }
  }

  const AuthenticationContainer = connect(state => ({
    isLogin: state.loginInfo.isLogin
  }))(Authentication);
  return ;
};

store/store.js

import { createStore, combineReducers, applyMiddleware } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import createSagaMiddleware from 'redux-saga'
import logger from 'redux-logger'
import * as login from './login/reducer'
import rootSaga from './sagas'
const sagaMiddleware = createSagaMiddleware();
const middlewares = [ sagaMiddleware, logger];
let store = createStore(
    combineReducers(login),
    composeWithDevTools(applyMiddleware(...middlewares))
);
sagaMiddleware.run(rootSaga);
export default store;

store/sagas/index.js

import { takeEvery, takeLatest, call, put, all } from 'redux-saga/effects';
import * as loginPro from '../login/action-types';
import {  login } from '../../service/api';

// worker saga
// Login
function* getLoginInfo(action) {
    try {
        const userInfo = yield call(login, action.param);
        if (userInfo.data.result.code === 10000) {
            yield put({ type: loginPro.LOGIN_INFO, userinfo: userInfo.data, isLogin: true })
        } else {
            yield put({ type: loginPro.LOGIN_INFO, userinfo: userInfo.data, isLogin: false })
        }

    } catch (e) {
        yield put({ type: loginPro.LOGIN_FAILIURE, error: e })
    }
}

// wacther saga
function* takeLogin() {
    yield takeLatest(loginPro.LOGIN_SUCCESS, getLoginInfo)
}



// root saga
export default function* rootSaga() {
    yield takeLogin()
}

store/login/action-types.js

export const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
export const LOGIN_INFO = 'LOGIN_INFO';
export const LOGIN_FAILIURE = 'LOGIN_FAILIURE';

store/login/action.js

import * as pro from './action-types'

export const login = (param) => {
    return (dispatch) => dispatch({
        type: pro.LOGIN_SUCCESS,
        param
    })
}

store/login/reducers.js

import * as pro from './action-types'
let defaultState = {
    userinfo: {},
    error: {}
}
export const loginInfo = (state = defaultState, action) => {
    switch (action.type) {
        case pro.LOGIN_INFO:
            return {...state, ...action }
        case pro.LOGIN_FAILIURE:
            return {...state, ...action }
        default:
            return state;
    }
}

service/api.js

import {instance} from './apiConfig';

export const login = (data) => {
    return instance.post('/login', data)
}

service/apiConfig.js

import axios from 'axios';
import Qs from 'qs';
import { Toast } from 'antd-mobile'
// 全局默认配置

// 设置 POST 请求头
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

// 在向服务器发送前,修改请求数据(只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法)
// 采用Qs的方式是为了用于application/x-www-form-urlencoded
axios.defaults.transformRequest = [(data) => { return Qs.stringify(data) }]


// 在传递给 then/catch 前,允许修改响应数据
// axios.defaults.transformResponse = [(data) => { return JSON.parse(data) }]

// 配置 CORS 跨域
// 表示跨域请求时是否需要使用凭证
axios.defaults.withCredentials = true;

axios.defaults.crossDomain = true;

// 设置超时
axios.defaults.timeout = 40000;


// 拦截器的说明
// 1、interceptor必须在请求前设置才有效。
// 2、直接为axios全局对象创建interceptor, 会导致全局的axios发出的请求或接收的响应都会被拦截到, 所以应该使用axios.create() 来创建单独的axios实例。

let instance = axios.create({
        baseURL: '',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        withCredentials: true,
    })


// Add a request interceptor
instance.interceptors.request.use(function(config) {

    // POST 请求参数处理成 axios post 方法所需的格式        
    if (config.method === 'post' || config.method === "put" || config.method === "delete") {
        //config.data = JSON.stringify(config.data);
    }
    Toast.loading('Loading...', 0, () => {
        console.log('Load complete !!!');
    });
    return config;
}, function(error) {
    // Do something with request error
    Toast.hide()
    return Promise.reject(error);
});

// Add a response interceptor
instance.interceptors.response.use(function(response) {
    // Do something with response data
    Toast.hide()
    return response.data;
}, function(error) {
    // Do something with response error
    Toast.hide()
    return Promise.reject(error);
});



export { instance };

index.js

import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import store from "./store/store";
import Route from "./router/";
import registerServiceWorker from "./registerServiceWorker";
import { AppContainer } from "react-hot-loader";


const render = Component => {
  ReactDOM.render(
    //绑定redux、热加载
    // Provider作为顶层组件,提供数据源,然后可以源源不断的从它向下流到各级子孙节点上去,所以Redux把store注册到Provider中
    // Provider接受一个属性store,这就是我们全局的数据store。我们要根据reducer函数来创建它
    
      
        
      
    ,
    document.getElementById("root")
  );
};

render(Route);

// Webpack Hot Module Replacement API
if (module.hot) {
  module.hot.accept("./router/", () => {
    render(Route);
  });
}
registerServiceWorker();

 

你可能感兴趣的:(React)