【问题标题】:Logout if token is expired如果令牌过期则注销
【发布时间】:2020-04-16 11:10:19
【问题描述】:

我正在开发一个包含许多 API 请求的反应应用程序。应用程序的结构是

登录时,我收到一个响应令牌,并将令牌保存在本地存储中以用于其他 API 请求。

此令牌每 30 分钟过期一次,如果我在 30 分钟后发出 API 请求,我的请求中将收到 401 状态。我正在使用这个 401 状态来注销并清除本地存储中的令牌数据。

示例请求

export function stationDailyUsage(data) {
    return dispatch => {
        dispatch(dailyUsageLoading());
        axios.get(`${API_URL}/Dashboard/DailyUsage?type=${data.type}&date=${data.date}`, {
            headers: {
                'Authorization': `Bearer ${token}`
            },
        })
            .then(res => {
                if (res.data.success === true) {
                    dispatch(dailyUsageSuccess(res.data));
                } else {
                    console.log("error");
                }
            })
            .catch(function (error) {
                if(error.response.status === 401){
                    dispatch(logout());
                }
              });
    }
}

因此,要以这种方式注销,我必须对我使用的每个 API(大约 40 个 API)进行此检查。这是最好的方法还是有更好的方法来处理注销。我读过axios interceptors,但不清楚如何在我的系统中实现它。非常感谢任何帮助。

【问题讨论】:

  • 我认为使用 axios 拦截器会更好,在您的情况下,您还应该获得 refresh token 以及身份验证令牌。因此,每当您在 30 分钟后进行第一次 API 调用并发现它显示 401 时,您应该使用该刷新令牌来获取新令牌并更新本地存储中的令牌。
  • 就我而言,我没有刷新令牌

标签: javascript reactjs redux axios token


【解决方案1】:

将此代码放入您的项目初始化或加载部分,并运行一次 那么每次你调用axios这个代码都会检查错误

在此处更改您的变量并使用它

  // Add a request interceptor
  axios.interceptors.request.use((config) => {
    let token = localStorage.getItem("token");
    if (token) {
      config.headers.credentials = 'include';
      config.headers.Authorization = `Bearer ${token}`;
      config.headers['Access-Control-Allow-Origin'] = '*';
      config.headers['Content-Type'] = 'application/json';
    }

    return config;
  }, (error) => {
    alert('interceptor request has error');
    return Promise.reject(error);
  });

  // Add a response interceptor
  axios.interceptors.response.use((response) => {
    return response;
  }, (error) => {

    if (error.response && error.response.data && error.response.data.error &&
      (error.response.data.session === false || error.response.data.session === "false")) {
      localStorage.removeItem("userId"); // <-- add your var
      window.location = "/";   // <-- add your path
    }
    else if (error.response && error.response.data && error.response.data.error && error.response.data.error.message) {
      toastMessage(error.response.data.error.message, 1);
    }
    else
      if (error.response && error.response.status === 401) {
        localStorage.removeItem("userId"); // <-- add your var
        window.location = "/";  // <-- add your path
      } else
        return Promise.reject(error);
  });

【讨论】:

    【解决方案2】:

    您可以为axios 编写自己的包装器,它应该是这样的:

    import axios from 'axios';
    
    const request = axios.create({
      baseURL: backUrl,
      timeout: 5000,
    });
    
    export const get = url => {
      const expiresIn = localStorage.getItem('expiresIn');
      const accessToken = localStorage.getItem('accessToken');
    
      if (expiresIn && Date.now() > expiresIn) {
        const refreshToken = localStorage.getItem('refreshToken');
        request
          .post('/oauth/token', {
            grant_type: 'refresh_token',
            refresh_token: refreshToken,
          })
          .then(res => {
            store.dispatch(
              loginSubmitted(
                res.data.access_token,
                res.data.refresh_token,
                res.data.expires_in,
              ),
            );
    
            localStorage.setItem('accessToken', res.data.access_token);
            localStorage.setItem('refreshToken', res.data.refresh_token);
            localStorage.setItem('expiresIn', res.data.expires_in);
    
            return request.get(url, {
              headers: { Authorization: `bearer ${res.data.access_token}` },
              accessToken: res.data.access_token,
            });
          })
          .catch(err => {
            localStorage.removeItem('accessToken');
            localStorage.removeItem('refreshToken');
            localStorage.removeItem('expiresIn');
          });
      }
    
      return request.get(url, {
        headers: { Authorization: `bearer ${accessToken}` },
        accessToken,
      });
    };
    
    

    所以它会在每个请求之前检查exprire_date 并发送一个新令牌的新请求,这样用户就不会注销

    【讨论】:

      【解决方案3】:

      是的,您部分正确,以防您无法使用刷新令牌(应该提供刷新令牌以保持理想的登录状态)。

      使用 axios 拦截器在响应变成需要处理的 401 之类的错误之前将其拦截。

      axios.interceptors.response.use(function (response) {
          // 200 type responses, this should be left as it is
          return response;
        }, function (error) {
          // Handle your 401 error, maybe the UI changes and removing from local storage
          return Promise.reject(error);
        });
      

      【讨论】:

        猜你喜欢
        • 2021-03-05
        • 2020-02-20
        • 1970-01-01
        • 2022-01-23
        • 2012-05-14
        • 2021-07-31
        • 2019-07-04
        • 2018-07-30
        • 2017-12-12
        相关资源
        最近更新 更多