gpt4 book ai didi

redux 刷新 token 中间件

转载 作者:行者123 更新时间:2023-12-01 13:29:24 25 4
gpt4 key购买 nike

我有一个中间件,可以在下一个操作运行之前转到刷新 token ,然后在访问 token 过期时运行另一个操作。

但是,如果我一次发出多个请求并且访问 token 已结束,我将尝试获取与请求一样多的刷新 token 。我正在检查状态中的 isLoading 属性以防止这种情况。但是请求之后,isLoading值在reducer中为true,在中间件中好像为false,所以一次又一次的请求。

我在 fetching_refresh_token 操作中发送 refreshTokenPromise,但我从来没有得到 state.refreshTokenPromise,它总是未定义的。

我肯定对国家有问题。

所以这是我的问题,如何访问中间件中不断变化的状态值?

刷新 token 中间件:(此版本多次命中端点)

import { AsyncStorage } from 'react-native';
import { MIN_TOKEN_LIFESPAN } from 'react-native-dotenv';
import moment from 'moment';
import Api from '../lib/api';
import {
FETCHING_REFRESH_TOKEN,
FETCHING_REFRESH_TOKEN_SUCCESS,
FETCHING_REFRESH_TOKEN_FAILURE } from '../actions/constants';

export default function tokenMiddleware({ dispatch, getState }) {
return next => async (action) => {
if (typeof action === 'function') {
const state = getState();
if (state) {
const expiresIn = await AsyncStorage.getItem('EXPIRES_IN');
if (expiresIn && isExpired(JSON.parse(expiresIn))) {
if (!state.refreshToken.isLoading) {
return refreshToken(dispatch).then(() => next(action));
}
return state.refreshTokenPromise.then(() => next(action));
}
}
}
return next(action);
};
}

async function refreshToken(dispatch) {
const clientId = await AsyncStorage.getItem('CLIENT_ID');
const clientSecret = await AsyncStorage.getItem('CLIENT_SECRET');
const refreshToken1 = await AsyncStorage.getItem('REFRESH_TOKEN');

const userObject = {
grant_type: 'refresh_token',
client_id: JSON.parse(clientId),
client_secret: JSON.parse(clientSecret),
refresh_token: refreshToken1,
};

const userParams = Object.keys(userObject).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(userObject[key])).join('&');

const refreshTokenPromise = Api.post('/token', userParams).then(async (res) => {
await AsyncStorage.setItem('ACCESS_TOKEN', res.access_token);
await AsyncStorage.setItem('REFRESH_TOKEN', res.refresh_token);
await AsyncStorage.setItem('EXPIRES_IN', JSON.stringify(res['.expires']));

dispatch({
type: FETCHING_REFRESH_TOKEN_SUCCESS,
data: res,
});

return res ? Promise.resolve(res) : Promise.reject({
message: 'could not refresh token',
});
}).catch((err) => {
dispatch({
type: FETCHING_REFRESH_TOKEN_FAILURE,
});

throw err;
});

dispatch({
type: FETCHING_REFRESH_TOKEN,
refreshTokenPromise,
});

return refreshTokenPromise;
}

function isExpired(expiresIn) {
return moment(expiresIn).diff(moment(), 'seconds') < MIN_TOKEN_LIFESPAN;
}

刷新 token 减少器:
import {
FETCHING_REFRESH_TOKEN,
FETCHING_REFRESH_TOKEN_SUCCESS,
FETCHING_REFRESH_TOKEN_FAILURE } from '../actions/constants';

const initialState = {
token: [],
isLoading: false,
error: false,
};

export default function refreshTokenReducer(state = initialState, action) {
switch (action.type) {
case FETCHING_REFRESH_TOKEN:
return {
...state,
token: [],
isLoading: true,
};
case FETCHING_REFRESH_TOKEN_SUCCESS:
return {
...state,
isLoading: false,
token: action.data,
};
case FETCHING_REFRESH_TOKEN_FAILURE:
return {
...state,
isLoading: false,
error: true,
};
default:
return state;
}
}

同时,当我将它发送到 getState 到 refreshToken 函数时,我得到了 refreshToken 中不断变化的状态值。但是在这个版本中,刷新 token 没有被刷新就去执行其他操作。

Monkey 补丁版本:(此版本仅发出 1 个请求)
import { AsyncStorage } from 'react-native';
import { MIN_TOKEN_LIFESPAN } from 'react-native-dotenv';
import moment from 'moment';
import Api from '../lib/api';
import {
FETCHING_REFRESH_TOKEN,
FETCHING_REFRESH_TOKEN_SUCCESS,
FETCHING_REFRESH_TOKEN_FAILURE } from '../actions/constants';

export default function tokenMiddleware({ dispatch, getState }) {
return next => async (action) => {
if (typeof action === 'function') {
const state = getState();
if (state) {
const expiresIn = await AsyncStorage.getItem('EXPIRES_IN');
if (expiresIn && isExpired(JSON.parse(expiresIn))) {
if (!state.refreshTokenPromise) {
return refreshToken(dispatch, getState).then(() => next(action));
}
return state.refreshTokenPromise.then(() => next(action));
}
}
}
return next(action);
};
}

async function refreshToken(dispatch, getState) {
const clientId = await AsyncStorage.getItem('CLIENT_ID');
const clientSecret = await AsyncStorage.getItem('CLIENT_SECRET');
const refreshToken1 = await AsyncStorage.getItem('REFRESH_TOKEN');

const userObject = {
grant_type: 'refresh_token',
client_id: JSON.parse(clientId),
client_secret: JSON.parse(clientSecret),
refresh_token: refreshToken1,
};

if (!getState().refreshToken.isLoading) {
const userParams = Object.keys(userObject).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(userObject[key])).join('&');

const refreshTokenPromise = Api.post('/token', userParams).then(async (res) => {
await AsyncStorage.setItem('ACCESS_TOKEN', res.access_token);
await AsyncStorage.setItem('REFRESH_TOKEN', res.refresh_token);
await AsyncStorage.setItem('EXPIRES_IN', JSON.stringify(res['.expires']));

dispatch({
type: FETCHING_REFRESH_TOKEN_SUCCESS,
data: res,
});

return res ? Promise.resolve(res) : Promise.reject({
message: 'could not refresh token',
});
}).catch((err) => {
dispatch({
type: FETCHING_REFRESH_TOKEN_FAILURE,
});

throw err;
});

dispatch({
type: FETCHING_REFRESH_TOKEN,
refreshTokenPromise,
});

return refreshTokenPromise;
}
}

function isExpired(expiresIn) {
return moment(expiresIn).diff(moment(), 'seconds') < MIN_TOKEN_LIFESPAN;
}

谢谢你。

最佳答案

我使用 axios 中间件解决了这个问题。我觉得还挺好看的。

import { AsyncStorage } from 'react-native';
import Config from 'react-native-config';
import axios from 'axios';
import { store } from '../store';
import { refreshToken } from '../actions/refreshToken'; // eslint-disable-line

const instance = axios.create({
baseURL: Config.API_URL,
});

let authTokenRequest;

function resetAuthTokenRequest() {
authTokenRequest = null;
}

async function getAuthToken() {
const clientRefreshToken = await AsyncStorage.getItem('clientRefreshToken');

if (!authTokenRequest) {
authTokenRequest = store.dispatch(refreshToken(clientRefreshToken));

authTokenRequest.then(
() => {
const {
token: { payload },
} = store.getState();

// save payload to async storage
},
() => {
resetAuthTokenRequest();
},
);
}

return authTokenRequest;
}

instance.interceptors.response.use(
response => response,
async (error) => {
const originalRequest = error.config;

if (
error.response.status === 401
&& !originalRequest._retry // eslint-disable-line no-underscore-dangle
) {
return getAuthToken()
.then(() => {
const {
token: {
payload: { 'access-token': accessToken, client, uid },
},
} = store.getState();

originalRequest.headers['access-token'] = accessToken;
originalRequest.headers.client = client;
originalRequest.headers.uid = uid;
originalRequest._retry = true; // eslint-disable-line no-underscore-dangle

return axios(originalRequest);
})
.catch(err => Promise.reject(err));
}

return Promise.reject(error);
},
);

export default instance;

如果你有问题,不要犹豫,问。

关于redux 刷新 token 中间件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46759321/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com