如何在Redux Thunk与Axios实例中获取useAuth0钩子数据
问题描述
项目基于Redux、@reduxjs/toolkit、react-redux实现状态管理,通过redux-thunk结合axios发起HTTP请求,同时集成Auth0处理用户注册与登录。当前核心问题是:非React组件/钩子的axios实例文件和thunk文件无法使用@auth0/auth0-react的useAuth0钩子,但需要在axios实例中访问getAccessTokenSilently、isAuthenticated、loginWithRedirect等Auth0数据来动态更新请求授权令牌,且希望避免在每个调用thunk的React组件中重复执行Auth0检查逻辑。
解决方案:通过Redux Thunk注入Auth0实例
核心思路是在根组件中获取Auth0实例,将其作为额外参数传递给Redux Thunk中间件,使thunk和axios实例能直接访问Auth0方法,无需在组件层重复处理认证逻辑。
步骤1:修改根组件,传递Auth0实例给Store
在根组件中通过useAuth0获取实例,创建Store时将其传入:
import React from 'react'; import { Provider } from 'react-redux'; import { useAuth0 } from '@auth0/auth0-react'; import createStore from '../store/createStore'; const App = () => { const auth0 = useAuth0(); const store = createStore(undefined, auth0); return ( <Provider store={store}> {/* 应用业务组件 */} </Provider> ); }; export default App;
步骤2:配置Store,为Thunk注入Auth0实例
修改createStore函数,将Auth0实例作为extraArgument传递给thunk中间件:
/* eslint-disable import/no-cycle */ import { configureStore } from '@reduxjs/toolkit'; import thunk from 'redux-thunk'; const createStore = (initialState?: any, auth0?: any) => { return configureStore({ reducer: { // 项目reducer定义 }, middleware: [thunk.withExtraArgument(auth0)], preloadedState: initialState, }); }; export default createStore;
步骤3:改造Axios实例,接收Auth0参数
将axios实例改为接收Auth0实例的函数,在内部处理令牌逻辑:
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'; import { getAuthSignature } from '../utils/auth'; export const API_URL = process.env.API_HOST; const axiosInstance = async <T = any>(requestConfig: AxiosRequestConfig, auth0: any): Promise<AxiosResponse<T>> => { const { token } = await getAuthSignature(); const { getAccessTokenSilently, isAuthenticated, loginWithRedirect } = auth0; let accessToken = token; // 处理Auth0令牌更新逻辑 if (auth0) { if (isAuthenticated) { try { accessToken = await getAccessTokenSilently({ audience: '你的API Audience' }); } catch (err) { loginWithRedirect(); throw new Error('获取Auth0访问令牌失败'); } } else { loginWithRedirect(); throw new Error('用户未认证'); } } if (!accessToken) { throw { title: '错误', message: '缺少认证令牌', success: false, }; } try { return await axios({ ...requestConfig, headers: { ...requestConfig.headers, authorization: `Bearer ${accessToken}`, }, }); } catch (error: any) { if (error.response?.status && [401, 403].includes(error.response.status)) { loginWithRedirect(); } const contentType = error?.response?.headers?.['content-type']; const isHTMLRes = contentType && contentType.indexOf('text/html') !== -1; throw { status: error?.response?.status, statusText: error?.response?.statusText, errorMessage: isHTMLRes && error?.response?.text ? await error.response.text() : undefined, error, }; } }; export default axiosInstance;
步骤4:更新Thunk Action,从额外参数获取Auth0实例
Thunk函数可通过第三个参数接收注入的Auth0实例,传递给axios实例:
import axiosInstance, { API_URL } from '../../services/axios'; import { Result } from '../../types/test'; import { setResults, setResultsLoading, setTableLoading } from './test.slice'; const getResults = () => async (dispatch, getState, auth0) => { dispatch(setTableLoading(true)); try { const result = await axiosInstance<Result[]>( { method: 'GET', url: `${API_URL}/test`, }, auth0 ); dispatch(setResults(result.data)); } catch (err: any) { console.error(err); } finally { dispatch(setResultsLoading(false)); dispatch(setTableLoading(false)); } }; export default getResults;
步骤5:组件调用无需修改
组件依然直接dispatch thunk即可,认证逻辑已在底层封装:
import React, { useEffect } from 'react'; import { useDispatch } from 'react-redux'; import getResults from '../../reducers/test/test.thunk'; const TestComponent = () => { const dispatch = useDispatch(); useEffect(() => { dispatch(getResults()); }, [dispatch]); return ( {/* 组件UI内容 */} ); }; export default TestComponent;
内容的提问来源于stack exchange,提问作者mcclosa
相关产品推荐
相关产品推荐

