如何在内存反应中正确存储访问令牌

And*_*zo1 9 javascript typescript reactjs

我正在寻找一种干净的方法来在 React 中存储我的访问令牌。

  • 第一件事:我不想使用本地存储。我不需要使我的访问令牌持久化,因为我可以随时刷新它。
  • 我还排除了 cookie,因为我想防止 CSRF 攻击。通过仅将访问令牌存储在内存中,实际上需要加载页面才能获取令牌并验证请求(刷新令牌只能用于刷新)
  • 我想过使用 redux/context,但是,调用 API 的函数不是组件的子组件,因此我无法从中访问令牌。此外,我不想将令牌作为参数传递,因为我想保持 HTTP 逻辑的解耦。也许有一种干净的方法来使用它?

经过一番研究,我发现使用全局变量是获得我想要的东西的有效“欺骗”。但是,我猜测是否有更清晰的方法来获得相同的结果。

//token.js

const access_token= "";

export const setAccessToken(token){
 access_token=token;
}

export const getAccessToken(){
 return access_token;
}

//NOTICE:
// -ON LOGIN/REFRESH: I set the access token
// -ON API CALLS: I get the access token and I add it to the header
Run Code Online (Sandbox Code Playgroud)
api.js

const baseURL= "http://my_base_url";

const generateApiInterface = ()=>{
    let headers : any= {
       
    };
    
    token=getAccessToken(); //HERE I NEED TO RETRIEVE MY ACCESS TOKEN

    if(token){
        headers={
            'Authorization': 'Token '+ token,
            ...headers //append other basic proprieties
        }
    }

    return axios.create({
        baseURL: baseURL,
        headers: headers
    });
}

const api = generateApiInterface();

Run Code Online (Sandbox Code Playgroud)

Kob*_*obe 5

您这样做的方式最好将所有内容都保留在内存中。如果这是服务器端,那么您需要确保完成后删除令牌,但如果不是,那么当前的方法是可取的。请注意,您正在使用 a const,您希望将其更改为 a let。另一个想法是使用会话存储,但这带来了 XSS 的想法。

然而,React 提供了一种拥有“全局”状态的方法 - 这将是使用提供者和上下文。这是一个例子:

// provider.tsx

import React, { useContext, createContext, FC, useState } from 'react'

type AccessTokenContext = [string, React.Dispatch<React.SetStateAction<string>>]

const AccessTokenProvider: FC = (props) => {
    const [accessToken, setAccessToken] = useState<string>(null)
    return <AccessToken.Provider value={[accessToken, setAccessToken]} {...props} />
}

const AccessToken = createContext<AccessTokenContext>(null)

const useAccessToken = (): AccessTokenContext => useContext<AccessTokenContext>(AccessToken)

export { AccessTokenProvider, useAccessToken }
Run Code Online (Sandbox Code Playgroud)

您必须将应用程序容器包装在AccessTokenProvider

// index.tsx

import React from 'react'
import ReactDOM from 'react-dom'

import './index.css'

import App from './App'
import { AccessTokenProvider } from './providers/AccessTokenProvider'

ReactDOM.render(
    <AccessTokenProvider>
        <App />
    </AccessTokenProvider>,
    document.getElementById('app')
)
Run Code Online (Sandbox Code Playgroud)

useAccessToken然后您就可以使用中的钩子App以及 的任何子级App。当然,该提供程序不必是根级别,但将其包含在此处是最简单的。

// app.tsx

import React, { FC } from 'react'

const App: FC = props => {
    const [accessToken, setAccessToken] = useAccessToken()
    return <div>{/* content */}</div>
}

export default App
Run Code Online (Sandbox Code Playgroud)