尝试使用 useSignOut 钩子时,无法在顶层调用 React Hook“useSetupInterceptors”

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

我正在尝试学习react js和springboot应用程序,当java重新启动时,我使jwt令牌中的tokenVersion(jwt负载中的时间戳而不是实际令牌)无效。

当java重新启动时,如果我尝试重新加载反应页面或导航Spring安全抛出403禁止。

使用我正在检查的响应并尝试强制用户注销并尝试使用signOut挂钩来清理状态或会话,但我收到了反应挂钩错误。

我从聊天gpt中尝试了很多方法,但没有一个给出解决方案。

这些是我的以下反应代码:

1。 EndpointConfig.js

import axios from 'axios';
import useSetupInterceptors from '../util/useSetupInterceptors'
const config = window.APP_CONFIG;
const endPointURLIP = config.endPointIP;
const defaultUrl = "localhost";
if(!endPointURLIP)
  endPointURLIP = defaultUrl;

  //Retrieving Token from the cookie which saved while login.
  const getTokenFromCookie = () => {
      const cookies = document.cookie.split(';').map(cookie => cookie.trim());
      for (const cookie of cookies) {
          if (cookie.startsWith('_auth=')) {
              const tokenCookie = cookie.split('=');
              if (tokenCookie.length === 2) {
                  return tokenCookie[1];
              }
          }
      }

      return null; // Token not found in cookies
  };
  const authToken = getTokenFromCookie();

  const getAxiosHeader = () => {
    const API_BASE_URL = 'http://'+endPointURLIP+':9081';
    const AUTHENTICATION_HEADER_TOKEN = authToken ? `Bearer ${authToken}` : null;

    return axios.create({
      baseURL: API_BASE_URL,
      headers: {
        Authorization: AUTHENTICATION_HEADER_TOKEN,
      },
    });
  };
  const authAxiosHeader = getAxiosHeader();
  useSetupInterceptors(authAxiosHeader);


  const endpointConfig = {
    a: 'http://'+endPointURLIP+':9081',
     HISTORY_ENDPOINT: '/demo/history',

    AUTHENTICATION_HEADER_TOKEN: authToken ? `Bearer ${authToken}` : null,
    AUTHENTICATION_HEADER:authAxiosHeader,
  };

export default endpointConfig;

2。 useSetupInterceptors.js

import { useEffect } from 'react';
import { useSignOut } from 'react-auth-kit';

const useSetupInterceptors = ({ axiosInstance }) => {
  const signOut = useSignOut();
  useEffect(() => {
    const interceptor = axiosInstance.interceptors.response.use(
      (response) => response,
      (error) => {
        if (error.response && error.response.status === 403) {
          alert('Request failed with status code 403:', error.message);
          handleLogout();
        }
        return Promise.reject(error);
      }
    );


  const handleLogout = () => {
      window.location.href = '/';
      signOut();
  };
 return () => {
 axiosInstance.interceptors.response.eject(interceptor);
 };
 }, [axiosInstance, signOut]);

};

export default useSetupInterceptors;

3. DemoService.js

import axios from 'axios';
import endpointConfig from './EndpointConfig';

class DemoService {

  constructor() {
    this.baseUrl = endpointConfig.API_BASE_URL;
    this.getHistoryEndpoint = endpointConfig.HISTORY_ENDPOINT;
    this.axiosHeader = endpointConfig.AUTHENTICATION_HEADER;
  }
  async getDemoHistory() {
    try {
      const response = await this.axiosHeader.get(`${this.getHistoryEndpoint}`);
      const configData = response.data;
      return configData;
    } catch (error) {
      console.log('Error retrieving data:'+error);
    }
  }
}
export default new DemoService();

DemoHistory.js

import React, { Component } from 'react';
import { DataTable } from 'primereact/datatable';
import { Column } from 'primereact/column';
import DemoService from '../services/DemoService';

class DemoHistory extends Component {
  constructor(props) {
    super(props);
    this.state = {
      resultFromController: [],
      isLoading: true,
    };
  }

  componentDidMount() {
    this.getDemoHistory();
  }

  getDemoHistory = () => {
    DemoService.getDemoHistory()
      .then((res) => {
        this.setState({ resultFromController: res, isLoading: false });
      })
      .catch((error) => {
        console.error('Error fetching Demo history:', error);
        this.setState({ isLoading: false });
      });
  };

  render() {
    const { resultFromController, isLoading } = this.state;

    if (isLoading) {
      return <div>Loading...</div>;
    }

    return (
      <div>
        <h1>Demo History</h1>
        <DataTable value={resultFromController}>
          <Column field="fromUser" header="From User" />
          <Column field="toUser" header="To User" />
        </DataTable>
      </div>
    );
  }
}

export default DemoHistory;

App.js

import React from 'react';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import { AuthProvider, RequireAuth } from 'react-auth-kit';
import DemoHistory from './components/DemoHistory';

function App() {
  return (
    <AuthProvider
      authType={"cookie"}
      authName={"_auth"}
      cookieDomain={window.location.hostname}
      cookieSecure={false}
    >
      <div>
        <h2 className="header_name">Demo</h2>
        <BrowserRouter>
          <Routes>
            <Route path="DemoHistory" element={<RequireAuth loginPath="/"><DemoHistory /></RequireAuth>} />
          </Routes>
        </BrowserRouter>
      </div>
    </AuthProvider>
  );
}

export default App;

登录.js

import React, { useState } from "react";
import { Button, Form } from 'react-bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';
import { useNavigate } from "react-router-dom";
import { useAuthHeader, useSignIn ,useSignOut } from "react-auth-kit";
import LoginService from "../services/LoginService";

export default function Login() {
  const [loginId, setLoginId] = useState("");
  const [password, setPassword] = useState("");
  const loginService = new LoginService();
  const navigate = useNavigate();
  const { setAuth, setHeader } = useAuthHeader();
  const signIn = useSignIn();
  const [loginStatus, setLoginStatus] = useState(null);

  function validate() {
    return loginId.length > 0 && password.length > 0;
  }

  async function submit(event) {
  try{
    event.preventDefault();
    loginService.setLoginId(loginId);
    loginService.setPassword(password);
    const result = await loginService.validateLogin(loginId,password);
    if (result && result.response === "success") {
          signIn({
            token: result.token,
            expiresIn: 24*60*60,//24 hours
            tokenType: "Bearer",
            authState: { username: "admin" },
          });
          window.location.href = "/history";
    } else {
      setLoginStatus("invalid");
      console.log("Login failed...");
    }
    }catch(error){
        setLoginStatus("invalid");
        console.log("Error While login."+error);
    }
  }

  return (
    <form
      name="vishing_form"
      method="post"
      className="login_tab_form"
      onSubmit={submit}
    >
      <p align="center" style={{ fontWeight: 'bolder', fontSize: '18px', fontFamily: 'helvetica' }}>
        RedShift Login
      </p>
      <div>
        <label>Login ID</label>
        <input className="loginTextField"
          autoFocus
          type="text"
          value={loginId}
          onChange={(e) => setLoginId(e.target.value)}
        />
      </div>
      <div>
        <label>Password</label>
        <input className="loginTextField"
          type="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
        />
      </div>
          {loginStatus === "invalid" && (
            <p>
              Invalid credentials. Please try again.
            </p>
          )}
      <div>
        <button
          id="submit"
          type="submit"
          name="login"
          className="submitBtn"
          disabled={!validate()}
        >
          Login
        </button>
      </div>
      </div>
    </form>
  );
}

错误:

Compiled with problems:
ERROR
[eslint] 
src\services\EndpointConfig.js
  Line 38:3:  React Hook "useSetupInterceptors" cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function  react-hooks/rules-of-hooks

我正在尝试学习 React js,请帮助如何解决此问题或任何更好的方法来处理会话管理和浏览器关闭处理

谢谢

reactjs react-hooks spring-security jwt
1个回答
0
投票

您无法在 React 组件和自定义 React hook 之外调用 React hook。您可以将

useSetupInterceptors
钩子调用移至 React 代码中。

这是一个使用在

AuthProvider
中渲染的本地组件的示例,以便它可以调用
useSetupInterceptors
钩子,并且
useSetupInterceptors
钩子可以引用 `react-auth-kit' 中的
useSignOut
钩子;

EndpointConfig.js

import axios from 'axios';
import useSetupInterceptors from '../util/useSetupInterceptors';

const config = window.APP_CONFIG;
const endPointURLIP = config.endPointIP;
const defaultUrl = "localhost";

if (!endPointURLIP) {
  endPointURLIP = defaultUrl;
}

const getTokenFromCookie = () => {
  const [, token = null] = document.cookie
    .split(";")
    .map(cookie => cookie.trim().split("="))
    .find(([key, value]) => key === "_auth") ?? [];
  return token;
};

const authToken = getTokenFromCookie();

const getAxiosInstance = () => {
  const API_BASE_URL = 'http://' + endPointURLIP + ':9081';
  const AUTHENTICATION_HEADER_TOKEN = authToken ? `Bearer ${authToken}` : null;

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

export const authAxiosInstance = getAxiosInstance(); // <-- export for app usage

const endpointConfig = {
  a: 'http://'+endPointURLIP+':9081',
  HISTORY_ENDPOINT: '/demo/history',
  AUTHENTICATION_HEADER_TOKEN: authToken ? `Bearer ${authToken}` : null,
  AUTHENTICATION_HEADER: authAxiosInstance,
};

export default endpointConfig;
import React from 'react';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import { AuthProvider, AuthOutlet } from 'react-auth-kit';
import DemoHistory from './components/DemoHistory';
import useSetupInterceptors from '../util/useSetupInterceptors';
import { authAxiosInstance } from './EndpointConfig';

const SetupAxios = () => {
  useSetupInterceptors(authAxiosInstance);

  return null;
};

function App() {
  return (
    <AuthProvider
      authType={"cookie"}
      authName={"_auth"}
      cookieDomain={window.location.hostname}
      cookieSecure={false}
    >
      <BrowserRouter>
        <SetupAxios />
        <div>
          <h2 className="header_name">Demo</h2>
          <Routes>
            <Route element={<AuthOutlet fallbackPath='/' />}>
              <Route path="DemoHistory" element={<DemoHistory />} />
            </Route>
            ...
          </Routes>
        </div>
      </BrowserRouter>
    </AuthProvider>
  );
}

export default App;
© www.soinside.com 2019 - 2024. All rights reserved.