Its*_*rge 13 typescript reactjs auth0 axios
我正在使用用户在登录时提供的 auth0 令牌通过 useAuth0.getTokenSilently 进行 api 调用。
在此示例中fetchTodoList
,addTodoItem
、 和updateTodoItem
都需要令牌进行授权。我希望能够将这些函数提取到一个单独的文件中(例如utils/api-client.js
并导入它们而无需显式传入令牌。
import React, { useContext } from 'react'
import { Link, useParams } from 'react-router-dom'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faCircle, faList } from '@fortawesome/free-solid-svg-icons'
import axios from 'axios'
import { queryCache, useMutation, useQuery } from 'react-query'
import { TodoItem } from '../models/TodoItem'
import { TodoInput } from './TodoInput'
import { TodoList as TodoListComponent } from './TodoList'
import { TodoListsContext } from '../store/todolists'
import { TodoListName } from './TodoListName'
import { TodoList } from '../models/TodoList'
import { useAuth0 } from '../utils/react-auth0-wrapper'
export const EditTodoList = () => {
const { getTokenSilently } = useAuth0()
const fetchTodoList = async (todoListId: number): Promise<TodoList> => {
try {
const token = await getTokenSilently!()
const { data } = await axios.get(
`/api/TodoLists/${todoListId}`,
{
headers: {
Authorization: `Bearer ${token}`
}
}
)
return data
} catch (error) {
return error
}
}
const addTodoItem = async (todoItem: TodoItem): Promise<TodoItem> => {
try {
const token = await getTokenSilently!()
const { data } = await axios.post(
'/api/TodoItems',
todoItem,
{
headers: {
Authorization: `Bearer ${token}`,
}
}
)
return data
} catch (addTodoListError) {
return addTodoListError
}
}
const updateTodoItem = async (todoItem: TodoItem) => {
try {
const token = await getTokenSilently!()
const { data } = await axios.put(
'/api/TodoItems',
todoItem,
{
headers: {
Authorization: `Bearer ${token}`,
}
}
)
return data
} catch (addTodoListError) {
return addTodoListError
}
}
const [updateTodoItemMutation] = useMutation(updateTodoItem, {
onSuccess: () => {
queryCache.refetchQueries(['todoList', todoListId])
}
})
const [addTodoItemMutation] = useMutation(addTodoItem, {
onSuccess: () => {
console.log('success')
queryCache.refetchQueries(['todoList', todoListId])
}
})
const onAddTodoItem = async (todoItem: TodoItem) => {
try {
await addTodoItemMutation({
...todoItem,
todoListId: parseInt(todoListId, 10)
})
} catch (error) {
// Uh oh, something went wrong
}
}
const { todoListId } = useParams()
const { status, data: todoList, error } = useQuery(['todoList', todoListId], () => fetchTodoList(todoListId))
const { todoLists, setTodoList } = useContext(TodoListsContext)
const todoListIndex = todoLists.findIndex(
list => todoListId === list.id.toString()
)
const setTodoItems = (todoItems: TodoItem[]) => {
// if(todoList) {
// const list = { ...todoList, todoItems }
// setTodoList(todoListIndex, list)
// }
}
const setTodoListName = (name: string) => {
// setTodoList(todoListIndex, { ...todoList, name })
}
return (
<>
<Link className="block flex align-items-center mt-8" to="/">
<span className="fa-layers fa-fw fa-3x block m-auto group">
<FontAwesomeIcon
icon={faCircle}
className="text-teal-500 transition-all duration-200 ease-in-out group-hover:text-teal-600"
/>
<FontAwesomeIcon icon={faList} inverse transform="shrink-8" />
</span>
</Link>
{status === 'success' && !!todoList && (
<>
<TodoListName
todoListName={todoList.name}
setTodoListName={setTodoListName}
/>
<TodoInput
onAddTodoItem={onAddTodoItem}
/>
<TodoListComponent
todoItems={todoList.todoItems}
setTodoItems={setTodoItems}
updateTodo={updateTodoItemMutation}
/>
</>
)}
</>
)
}
Run Code Online (Sandbox Code Playgroud)
这是 repo 的链接:https : //github.com/gpspake/todo-client
小智 11
我在如何getAccessTokenSilently
在 React 组件之外使用时遇到了类似的问题,我最终得到的是:
我的 HTTP 客户端包装器
export class HttpClient {
constructor() {
HttpClient.instance = axios.create({ baseURL: process.env.API_BASE_URL });
HttpClient.instance.interceptors.request.use(
async config => {
const token = await this.getToken();
return {
...config,
headers: { ...config.headers, Authorization: `Bearer ${token}` },
};
},
error => {
Promise.reject(error);
},
);
return this;
}
setTokenGenerator(tokenGenerator) {
this.tokenGenerator = tokenGenerator;
return this;
}
getToken() {
return this.tokenGenerator();
}
}
Run Code Online (Sandbox Code Playgroud)
在我的应用程序根目录中,我通过getAccessTokenSilently
auth0
useEffect(() => {
httpClient.setTokenGenerator(getAccessTokenSilently);
}, [getAccessTokenSilently]);
Run Code Online (Sandbox Code Playgroud)
就是这样!
您现在有一个axios
实例准备好执行经过身份验证的请求
好的,我知道了!
现在我更好地理解了,我真正的问题是如何向 axios 请求提供 auth0 令牌,以便不需要在组件中声明它们。
简短的答案:在初始化 auth0 时获取令牌并注册axios 拦截器以将该令牌设置为所有 axios 请求的标头值。
长答案(打字稿中的示例):
声明一个接受令牌并注册axios 拦截器的函数
const setAxiosTokenInterceptor = async (accessToken: string): Promise<void> => {
axios.interceptors.request.use(async config => {
const requestConfig = config
if (accessToken) {
requestConfig.headers.common.Authorization = `Bearer ${accessToken}`
}
return requestConfig
})
}
Run Code Online (Sandbox Code Playgroud)
在 auth0provider 包装器中,当 auth0 客户端初始化并经过身份验证时,获取令牌并将setAxiosTokenInterceptor
其传递给注册拦截器的函数(来自Auth0 React SDK Quickstart的修改示例):
useEffect(() => {
const initAuth0 = async () => {
const auth0FromHook = await createAuth0Client(initOptions)
setAuth0(auth0FromHook)
if (window.location.search.includes('code=')) {
const { appState } = await auth0FromHook.handleRedirectCallback()
onRedirectCallback(appState)
}
auth0FromHook.isAuthenticated().then(
async authenticated => {
setIsAuthenticated(authenticated)
if (authenticated) {
auth0FromHook.getUser().then(
auth0User => {
setUser(auth0User)
}
)
// get token and register interceptor
const token = await auth0FromHook.getTokenSilently()
setAxiosTokenInterceptor(token).then(
() => {setLoading(false)}
)
}
}
)
}
initAuth0().catch()
}, [])
Run Code Online (Sandbox Code Playgroud)
在解决 Promise 时调用setLoading(false)
可确保如果 auth0 加载完成,则拦截器已注册。由于在 auth0 完成加载之前不会呈现发出请求的任何组件,因此这可以防止在没有令牌的情况下进行任何调用。
这使我能够将所有 axios 函数移至一个单独的文件中,并将它们导入到需要它们的组件中。当调用这些函数中的任何一个时,拦截器会将令牌添加到标头中
utils/todo-client.ts
useEffect(() => {
const initAuth0 = async () => {
const auth0FromHook = await createAuth0Client(initOptions)
setAuth0(auth0FromHook)
if (window.location.search.includes('code=')) {
const { appState } = await auth0FromHook.handleRedirectCallback()
onRedirectCallback(appState)
}
auth0FromHook.isAuthenticated().then(
async authenticated => {
setIsAuthenticated(authenticated)
if (authenticated) {
auth0FromHook.getUser().then(
auth0User => {
setUser(auth0User)
}
)
// get token and register interceptor
const token = await auth0FromHook.getTokenSilently()
setAxiosTokenInterceptor(token).then(
() => {setLoading(false)}
)
}
}
)
}
initAuth0().catch()
}, [])
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2457 次 |
最近记录: |