在React Native中处理刷新令牌

时间:2019-09-22 16:48:00

标签: react-native redux axios refresh-token

我有一个可以通过身份验证并返回access_tokenrefresh_token的应用程序。我将它们与AsyncStorage存储在一起,并通过redux保存/获取access_token。这是我正在构建的第一个应用程序,我在如何以及在何处使用refresh_token方面感到困惑。

这是组件loginForm.js中的axios调用

axios({
                url: `${base}/oauth/token`,
                method: 'POST',
                data: formData,
                headers: {
                    Accept: 'application/json',
                    'Content-Type': 'multipart/form-data',
                }
            })
            .then(response => {
                setStatus({ succeeded: true });
                // console.log(response.data);
                deviceStorage.saveKey("userToken", response.data.access_token);
                deviceStorage.saveKey("refreshToken", response.data.refresh_token);
                Actions.main();
            })
            .catch(error => {
                if (error.response) {
                    console.log(error);
                }
            });

这是服务deviceStorage.js

import { AsyncStorage } from 'react-native';

const deviceStorage = {
    async saveItem(key, value) {
        try {
            await AsyncStorage.setItem(key, value);
        } catch (error) {
            console.log('AsyncStorage Error: ' + error.message);
        }
    }
};

export default deviceStorage;

这是令牌操作文件

import { AsyncStorage } from 'react-native';
import {
    GET_TOKEN,
    SAVE_TOKEN,
    REMOVE_TOKEN,
    LOADING_TOKEN,
    ERROR_TOKEN
} from '../types';

export const getToken = token => ({
    type: GET_TOKEN,
    token,
});

export const saveToken = token => ({
    type: SAVE_TOKEN,
    token
});

export const removeToken = () => ({
    type: REMOVE_TOKEN,
});

export const loading = bool => ({
    type: LOADING_TOKEN,
    isLoading: bool,
});

export const error = tokenError => ({
    type: ERROR_TOKEN,
    tokenError,
});

export const getUserToken = () => dispatch => 
    AsyncStorage.getItem('userToken')
        .then((data) => {
            dispatch(loading(false));
            dispatch(getToken(data));
        })
        .catch((err) => {
            dispatch(loading(false));
            dispatch(error(err.message || 'ERROR'));
        });

export const saveUserToken = (data) => dispatch =>
    AsyncStorage.setItem('userToken', data)
        .then(() => {
            dispatch(loading(false));
            dispatch(saveToken('token saved'));
        })
        .catch((err) => {
            dispatch(loading(false));
            dispatch(error(err.message || 'ERROR'));
        });

export const removeUserToken = () => dispatch =>
    AsyncStorage.removeItem('userToken')
        .then((data) => {
            dispatch(loading(false));
            dispatch(removeToken(data));
        })
        .catch((err) => {
            dispatch(loading(false));
            dispatch(error(err.message || 'ERROR'));
        });

这是代币减少器文件

import {
    GET_TOKEN,
    SAVE_TOKEN,
    REMOVE_TOKEN,
    LOADING_TOKEN,
    ERROR_TOKEN
} from '../actions/types';

const INITIAL_STATE = {
    token: {},
    loading: true,
    error: null
};

export default (state = INITIAL_STATE, action) => {
    switch (action.type) {
        case GET_TOKEN:
            return {
                ...state,
                token: action.token
            };
        case SAVE_TOKEN:
            return {
                ...state,
                token: action.token
            };
        case REMOVE_TOKEN:
            return {
                ...state,
                token: action.token
            };
        case LOADING_TOKEN:
            return {
                ...state,
                loading: action.isLoading
            };
        case ERROR_TOKEN:
            return {
                ...state,
                error: action.error
            };
        default:
            return state;
    }
};

这是身份验证文件

import React from 'react';
import {
    StatusBar,
    StyleSheet,
    View,
} from 'react-native';
import { connect } from 'react-redux';
import { Actions } from 'react-native-router-flux';
import { Spinner } from '../common';
import { getUserToken } from '../../actions';

class AuthLoadingScreen extends React.Component {

    componentDidMount() {
        this.bootstrapAsync();
    }

    bootstrapAsync = () => {
        this.props.getUserToken().then(() => {
            if (this.props.token.token !== null) {
                Actions.main();
            } else {
                Actions.auth();
            }
        })
            .catch(error => {
                this.setState({ error });
            });
    };

    render() {
        return (
            <View style={styles.container}>
                <Spinner />
                <StatusBar barStyle="default" />
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center'
    },
});

const mapStateToProps = state => ({
    token: state.token,
});


const mapDispatchToProps = dispatch => ({
    getUserToken: () => dispatch(getUserToken()),
});

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

我认为我需要创建一个动作和减速器来获得refresh_token(是正确的吗?),但是我不知道该如何处理以及在何处调用它(也许在身份验证文件中?)。 。 对于与此代码示例相关的代码方面的任何帮助,将不胜感激。谢谢

1 个答案:

答案 0 :(得分:0)

以下是步骤

执行Login,从响应中获取accessToken,refreshToken并将其保存到AsyncStorage。 为API调用设置通用功能

    async function makeRequest(method, url, params, type) {
      const token = await AsyncStorage.getItem('access_token');
    
      let options = {
        method: method,
        headers: {
          Accept: 'application/json',
          'Content-Type': 'application/json',
          Authorization: 'Bearer ' + token,
        },
      };
    
      if (!token) {
        delete options['Authorization'];
      }
    
      if (['GET', 'OPTIONS'].includes(method)) {
        url += (url.indexOf('?') === -1 ? '?' : '&') + queryParams(params);
      } else {
        Object.assign(options, {body: JSON.stringify(params)});
      }
    
      const response = fetch(ENV.API_URL+url, options);
    
      return response;
    }

在redux中为getAceessTokenFromRefreshToken做一个方法。 会话过期时使用此方法

您如何知道会话已过期?

在每个API调用中,如果您收到类似(440个响应代码)的响应,则


    async componentWillReceiveProps(nextProps) {
        if (nextProps.followResponse && nextProps.followResponse != this.props.followResponse) {
          if (nextProps.followResponse.status) {
          
      if (nextProps.followResponse.status == 440) {
                // call here get acceesstokenfrom refresh token method and save again accesstoken in asyncstorage and continue calling to API
            }
          }
        }
      }