Когда обновлять токен JWT?

#vue.js #laravel-5 #jwt-auth

#vue.js #laravel-5 #jwt-auth

Вопрос:

В настоящее время я использую JWT-Auth в своем серверном интерфейсе Laravel для защиты своих маршрутов API с помощью токена. Однако через определенное время токен становится недействительным, и я получаю сообщение об ошибке 401 Unauthorized . Так что, я думаю, мне нужно где-то обновить токен. Когда будет лучшее время для этого? Я читал об этом каждый раз, когда вы делаете запрос, но я хочу быть уверенным, что это правильный способ сделать это. Я использовал это руководство из их документов: https://jwt-auth.readthedocs.io/en/develop/quick-start/#create-the-authcontroller . Здесь они создают функцию для обновления токена. Но как мне реализовать это каждый раз, когда я делаю запрос? Я просто вызываю эту функцию в контроллере с Axios запросом или вызываю ее в другом контроллере или что-то в этом роде? Любые советы приветствуются.

У меня есть Vue.js интерфейс, между прочим.

Ответ №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)
}