在 React Native 中处理刷新令牌
Posted
技术标签:
【中文标题】在 React Native 中处理刷新令牌【英文标题】:Handling Refresh Token in React Native 【发布时间】:2020-01-22 20:54:01 【问题描述】:我有一个应用程序验证正常并返回access_token
和refresh_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 身份验证或您的自定义身份验证系统? 【参考方案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
【讨论】:
以上是关于在 React Native 中处理刷新令牌的主要内容,如果未能解决你的问题,请参考以下文章
用于 JWT 刷新令牌的 react-native 中的 httpOnly cookie
当 jwt 刷新令牌未过期时,React Native 应用程序注销
使用 redux saga 在 react native 中实现令牌刷新