401 Bearer token 生成后未经授权的请求

问题描述 投票:0回答:1

我有以下代码,其中我请求从 keycloak 获取承载令牌,并发出另一个请求以保存在浏览器编辑器上编写的内容(通过单击名为“保存”的按钮)。

这里的问题是:令牌仅持续 5 分钟,因此我想在调用 makeApiRequest 之前调用函数 getToken (生成新的有效令牌),以便请求正常运行。现在,当我运行应用程序后等待 5 分钟并单击“保存”时,我会收到未经授权的状态代码,例如未正确生成令牌第二次,但如果我再次单击“保存”按钮,它就会起作用(编辑器的内容是按预期保存)。下图是一个例子:

console print

这是我的js文件:

import React, { useEffect, useState } from 'react';
import { MyEditor } from '@myEditor/example-editor';

function MeEditor() {
  const tokenURL = 'http://keycloak:1902/auth/realms/myEditor/openid-connect/token';
  const apiURL = 'http://localhost:1777/MyEditor/api/note';
  const clientId = 'my_cli_client';
  const clientSecret = 'my_cli_client_secret';

  const [tokenInfo, setTokenInfo] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  const [isSaving, setIsSaving] = useState(false);
  const [editorText, setEditorText] = useState('');

  useEffect(() => {
    getToken();
  }, []);

  const getToken = async () => {
    const params = new URLSearchParams();

    params.append('grant_type', 'client_credentials');
    params.append('client_id', clientId);
    params.append('client_secret', clientSecret);

    const response = await fetch(tokenURL, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      body: params,
    });

    const data = await response.json();
    const expirationTime = new Date().getTime() + data.expires_in * 1000;

    setTokenInfo({
      accessToken: data.access_token,
      expiresAt: expirationTime,
    });
    setIsLoading(false);
  };

  const makeApiRequest = async () => {
    const postData = {
      data: {
        correlationId: 123,
        subjectId: '01',
        text: editorText,
      },
    };

    const response = await fetch(apiURL, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: 'Bearer ' + tokenInfo.accessToken,
      },
      body: JSON.stringify(postData),
    });

    if (response.ok) {
      const apiResponse = await response.json();
      console.log(apiResponse);
    } else {
      console.error('API request failed:', response.status, response.statusText);
    }
  };

  const handleSaveButtonClick = async () => {
    setIsSaving(true);
    const currentTime = new Date().getTime();

    if (!tokenInfo || currentTime > tokenInfo.expiresAt) {
      await getToken();
    }

    if (tokenInfo) {
      await makeApiRequest();
    }
    setIsSaving(false);
  };

  const handleEditorChange = (newText) => {
    setEditorText(newText);
  };

  return (
    <div className="editor-container">
      {isLoading ? (
        <p>Loading...</p>
      ) : tokenInfo ? (
        <React.Fragment>
          <MyEditor 
            tokenProvider={{ getToken: () => tokenInfo.accessToken }}
            defaultValue={editorText}
            onChange={handleEditorChange}
          />
          <button onClick={handleSaveButtonClick} disabled={isSaving}>
            {isSaving ? 'Saving...' : 'Save'}
          </button>
        </React.Fragment>
      ) : (
        <p>No token available.</p>
      )}
    </div>
  );
}

export default MyEditor;

知道我可能会错过什么吗?我尝试重构下面的验证,以在 makeApiRequest 之前生成一个新的有效令牌(如果旧的令牌不再有效),但到目前为止还没有运气

if (!tokenInfo || currentTime > tokenInfo.expiresAt) {
      await getToken();
    }
javascript reactjs react-hooks javascript-objects
1个回答
0
投票

我认为问题是由于 useEffect 造成的,您在 useEffect 中所做的更新不会立即可见,因为您使用了异步状态。问题应该出在

setTokenInfo({
      accessToken: data.access_token,
      expiresAt: expirationTime,
    });

你应该做类似的事情

setTokenInfo((lastToken) => { set new token information })
© www.soinside.com 2019 - 2024. All rights reserved.