当令牌在反应应用程序中过期时如何注销用户

man*_*kur 13 javascript reactjs graphql react-apollo react-hooks

我正在开发一个应用程序,我使用 React 作为我的前端和React-apollo-graphqlAPI 调用。

react-hooks在 React 16.8 + 中使用ie。

我在做什么

我已经创建了一个auth.js文件,当用户登录并检查令牌是否有效时,我将在其中存储我的值(我正在检查到期),但该文件仅加载我正在刷新或重新加载页面,那不是它应该如何工作

我的 auth.js 文件

const initialstate = {
    user: null,
};
if (localStorage.getItem("JWT_Token")) {
    const jwt_Token_decoded = Jwt_Decode(localStorage.getItem("JWT_Token"));
    console.log(jwt_Token_decoded.exp * 1000);
    console.log(Date.now());
    if (jwt_Token_decoded.exp * 1000 < Date.now()) {
        localStorage.clear(); // this runs only when I refresh the page or reload on route change it dosent work
    } else {
        initialstate.user = jwt_Token_decoded;
    }
}

const AuthContext = createContext({
    user: null,
    login: (userData) => {},
    logout: () => {},
});
const AuthReducer = (state, action) => {
    switch (action.type) {
        case "LOGIN":
        return {
            ...state,
            user: action.payload,
        };
        case "LOGOUT":
        return {
            ...state,
            user: null,
        };
        default:
        return state;
    }
};
    
const AuthProvider = (props) => {
    const [state, dispatch] = useReducer(AuthReducer, initialstate);
    const login = (userData) => {
        localStorage.setItem("JWT_Token", userData.token);
        dispatch({
        type: "LOGIN",
        payload: userData,
        });
    };
    const logout = () => {
        localStorage.clear();
        dispatch({ action: "LOGOUT" });
    };
    
    return (
        <AuthContext.Provider
        value={{ user: state.user, login, logout }}
        {...props}
        />
    );
};
    
export { AuthContext, AuthProvider };
Run Code Online (Sandbox Code Playgroud)

正如我评论的那样,我正在检查令牌到期的行。

我唯一的问题是当我们使用 Redux 时,为什么它在页面重新加载而不是像我们在存储文件中那样在每个路由上工作。

我的 App.js

<AuthProvider>
  <Router>
    <div className="App wrapper">
      <Routes/>
    </div>
  </Router>
</AuthProvider>
Run Code Online (Sandbox Code Playgroud)

我的 index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import ApolloClient from 'apollo-boost'
import { ApolloProvider } from '@apollo/react-hooks';
import { InMemoryCache } from 'apollo-cache-inmemory';
    
const client = new ApolloClient({
  uri: 'my url',
  cache: new InMemoryCache(),
});
ReactDOM.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>,
  document.getElementById('root')
);
Run Code Online (Sandbox Code Playgroud)

要点

正如我使用的react-apollo-graphql那样,他们是否提供蚂蚁身份验证流程?就像 redux 所做的那样,我们必须创建一个存储文件来存储我们的数据

我使用的是 React 16.8 +,所以我使用的是 react-hooks,所以这里我use Reducer只使用它。

我唯一的问题是我做得对吗?我对其他方法持开放态度。

我已经使用 Vuex 在 Vue 中完成了身份验证和授权,我用来创建一个在任何路线上运行的商店文件

我对 Redux 也做过同样的事情,在我的商店文件中,我用来存储状态和所有内容。

现在,如果我使用 react-hooks 和 react-apollo-graphql,则无需使用 redux 来做这些事情。

apollo-link-context用于传递标题(授权),如下所示

const authLink = setContext(() => {
  const token = localStorage.getItem('JWT_Token')
  return {
    headers:{
      Authorization: token ? `${token}` : ''
    }
  }
});
Run Code Online (Sandbox Code Playgroud)

我想在这里我可以检查每个路由或每个请求是否令牌有效(检查 exp 时间)如果它无效然后我将注销并清除我的本地存储,清除存储不是什么大问题是如何重定向到登录页面。

Shu*_*tri 10

您面临的问题很简单。您的 AuthReducer 在创建时只接收一次 initialState。现在,当您重新加载应用程序时,一切都会再次初始化,并且到期时间由您的逻辑处理。但是在 Route change 它不会重新评估您的 initialState。

但是,您可以做的是在使用时setContext您可以通过解码令牌来检查jwtDecode是否过期,如果令牌过期并刷新令牌并保存在 localStorage 中,因为这是在每个请求上执行的

const authLink = setContext(async () => {
  let token = localStorage.getItem('JWT_Token')
  const { exp } = jwtDecode(token)
  // Refresh the token a minute early to avoid latency issues
  const expirationTime = (exp * 1000) - 60000
  if (Date.now() >= expirationTime) {
    token = await refreshToken()
    // set LocalStorage here based on response;
  }
  return {
    // you can set your headers directly here based on the new token/old token
    headers: {
      ...
    }
  }
})
Run Code Online (Sandbox Code Playgroud)

但是,由于您希望重定向到登录页面而不是在令牌过期时刷新令牌,因此您可以使用自定义历史对象与 Routes

源代码/历史记录.js

import { createBrowserHistory } from 'history';
const history = createBrowserHistory()
export default history;
Run Code Online (Sandbox Code Playgroud)

应用程序.js

import history from '/path/to/history.js';
import { Router } from 'react-router-dom';

<AuthProvider>
  <Router history={history}>
    <div className="App wrapper">
      <Routes/>
    </div>
  </Router>
</AuthProvider>
Run Code Online (Sandbox Code Playgroud)

然后在 setContext 你可以做

import history from '/path/to/history';
const authLink = setContext(async () => {
  let token = localStorage.getItem('JWT_Token')
  const { exp } = jwtDecode(token)
  const expirationTime = (exp * 1000) - 60000
  if (Date.now() >= expirationTime) {
    localStorage.clear();
    history.push('/login');
  }
  return {
    // you can set your headers directly here based on the old token
    headers: {
      ...
    }
  }
})
Run Code Online (Sandbox Code Playgroud)