【问题标题】:Handling Refresh Token in React Native在 React Native 中处理刷新令牌
【发布时间】:2020-01-22 20:54:01
【问题描述】:

我有一个应用程序验证正常并返回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(对吗?)但我不知道如何处理它以及在哪里调用它(可能在身份验证文件中?)。 任何可能与我的代码相关的代码示例的帮助将不胜感激。谢谢

【问题讨论】:

  • 您在这方面取得了进展吗?我也有同样的问题
  • 您使用的是哪种身份验证? Google 登录、Facebook 登录、firebase 身份验证或您的自定义身份验证系统?

标签: react-native redux axios refresh-token


【解决方案1】:

以下是步骤

登录,从响应中获取 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 创建一个方法。 会话过期时使用此方法

你怎么知道会话过期了?

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


    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
            }
          }
        }
      }

【讨论】:

    猜你喜欢
    • 2014-08-01
    • 2014-06-15
    • 2020-09-11
    • 1970-01-01
    • 2018-01-20
    • 1970-01-01
    • 1970-01-01
    • 2020-05-26
    • 1970-01-01
    相关资源
    最近更新 更多