何时刷新JWT令牌?

时间:2019-04-15 16:45:31

标签: vue.js laravel-5 jwt-auth

当前,我在Laravel后端上使用JWT-Auth来通过令牌保护我的API路由。但是,经过一段时间后,令牌无效,并且出现错误401 Unauthorized。所以我想我必须在某个地方刷新令牌。什么时候是最好的时间?每当您提出请求时,我都会阅读有关这样做的信息,但我想确保这是正确的方法。我从他们的文档https://jwt-auth.readthedocs.io/en/develop/quick-start/#create-the-authcontroller中使用了本指南。在这里,它们提供了刷新令牌的功能。但是,每次提出请求时,我将如何实施呢?我是否只是通过Axios请求在控制器中调用此函数,还是在其他控制器中调用它?任何提示,不胜感激。

顺便说一下,我有一个Vue.js前端。

1 个答案:

答案 0 :(得分:1)

使用Tymon / JWTAuth,您有两个选择:

  • 您可以将jwt.refresh中间件添加到api路由,该中间件将在每次发出请求时刷新令牌。该解决方案的缺点是可能被滥用。好处是您不必真正担心应用程序中的令牌,特别是如果您没有前端或自己不开发前端时。
  • 您解析令牌客户端。 jwt令牌的前两个部分是完全公共的,并且已进行base64编码。您实际上不需要知道此令牌是否由服务器客户端签名,因此您可以放心地忽略最后一部分。如果您在api调用周围有一个包装程序来处理api调用的常见逻辑(例如,添加授权标头开头),则此解决方案相对容易。

const token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjEsImlzcyI6Imh0dHBzOi8vZXhhbXBsZS5jb20iLCJpYXQiOjE1NTUzNDkxMjYsImV4cCI6MTU1NTM3NzkyNiwibmJmIjoxNTU1MzQ5MTI2LCJqdGkiOiJtZEdTNGE2ZDJnNHM5NzRnNSJ9.TygbG5smlhAapE8fy4rgXlLVYW-qOcWtLYnnbgJCIKg";

function shouldRefreshToken(token) {
  const currentTime = 1555350309829; // Date.now()
  const universalTimestamp = currentTime / 1000;
  
  const gracePeriod = 60 * 60 * 8; // 8 hours

  const tokenParts = token.split('.');
  const payload = JSON.parse(atob(tokenParts[1]));
  
  if (payload.iat > universalTimestamp) {
    console.log("This monstrosity was issued in the future O_o");
  }
  
  if (payload.nbf > universalTimestamp) {
    console.log("This token is not valid yet. Refreshing it does not yield anything useful. Maybe we still have some previous token?");
  }
  
  if (payload.exp < universalTimestamp) {
    console.log("This token has expired. We should try to refresh it before doing anything else.");
  } else if (payload.exp - gracePeriod < universalTimestamp) {
    console.log("This token is about to expire. We can refresh it asynchronously.");
  } else {
    console.log("Nah, we are fine!");
  }
}

shouldRefreshToken(token);

最后,您希望将请求发送到执行此类操作的刷新终结点,然后由前端对其进行解析:

$myNewToken = JWTAuth::refresh(JWTAuth::getToken());
response()->header('Authorization', "Bearer {$myNewToken}");

要使其正常工作,您可以执行以下操作:

import store from '../store';
import { shouldRefreshToken } from '../helpers/auth';

const someBaseUrl = 'https://example.com';

export function request(options = {}) {
  // Hopefully you rewrite that function above to return a boolean ;-)
  if (shouldRefreshToken(store.state.auth.token)) {
    refreshToken();
  }

  const config = {
    method: options.method,
    url: `${someBaseUrl}/${options.resource}`,
    credentials: 'include',
    headers: {
      ...(options.headers || {}),
      Authorization: `Bearer ${store.state.auth.token}`,
      'Content-Type': 'application/json'
    },
    data: options.data
  }

  return axios(config).then(parseResponse)
}

function parseResponse(axiosResponse) {
  // Probably want to get the token and do something with it
}

function refreshToken() {
  axios({
    method: 'POST',
    url: `${someBaseUrl}/refresh`
  }).then(parseResponse)
}