瀏覽代碼

refresh token

CR026
Jason Chuang 3 週之前
父節點
當前提交
9a1ad6eebd
共有 4 個文件被更改,包括 93 次插入 和 38 次删除
  1. +16
    -34
      src/auth/index.js
  2. +3
    -2
      src/auth/jwt/jwtService.js
  3. +71
    -0
      src/auth/refreshGate.js
  4. +3
    -2
      src/components/RefreshTokenProvider.js

+ 16
- 34
src/auth/index.js 查看文件

@@ -14,6 +14,7 @@ import {useNavigate} from "react-router-dom";
import {useDispatch} from "react-redux";
import { LOGOUT, REFRESH_TOKEN } from 'utils/ApiPathConst';
import { getMessage } from 'utils/getI18nMessage';
import { beginRefresh } from 'auth/refreshGate';

// Guard so we only register interceptors once (ThemeRoutes re-renders add duplicate handlers otherwise)
let axiosInterceptorsSetup = false;
@@ -192,10 +193,10 @@ export const SetupAxiosInterceptors = () => {
return Promise.reject(error);
}
isRefreshToken = true;
return axios
return beginRefresh(() => axios
.post(`${apiPath}${REFRESH_TOKEN}`, {
refreshToken: refreshToken // Replace with your refresh token
})
refreshToken: refreshToken
}))
.then((response) => {
if (response.status === 200) {
const newAccessToken = response.data.accessToken;
@@ -261,36 +262,17 @@ export const SetupAxiosInterceptors = () => {
}

export const handleRefreshTokenFunction = () => {
// const token = localStorage.getItem('accessToken');
let isRefresh = false;
if (!isRefresh) {
const refreshToken = localStorage.getItem('refreshToken');
isRefresh = true;
axios.post(`${apiPath}${REFRESH_TOKEN}`, {
refreshToken: refreshToken
}).then((response) => {
if (response.status === 200) {
const newAccessToken = response.data.accessToken;
const newRefreshToken = response.data.refreshToken;
localStorage.setItem('accessToken', newAccessToken);
localStorage.setItem('refreshToken', newRefreshToken);
// token = newAccessToken;
isRefresh = false;
} else {
// token = null;
isRefresh = false;
}
})
.catch((refreshError) => {
console.log('Failed to refresh token');
if (refreshError != undefined){
console.log(refreshError)
}
// token = null
isRefresh = false;
});
const refreshToken = localStorage.getItem('refreshToken');
if (!refreshToken) {
return false;
}

return isRefresh;
beginRefresh(() => axios.post(`${apiPath}${REFRESH_TOKEN}`, {
refreshToken: refreshToken
})).catch((refreshError) => {
console.log('Failed to refresh token');
if (refreshError != undefined) {
console.log(refreshError)
}
});
return true;
}

+ 3
- 2
src/auth/jwt/jwtService.js 查看文件

@@ -1,5 +1,6 @@
import axios from 'axios'
import jwtDefaultConfig from './jwtDefaultConfig'
import { beginRefresh } from '../refreshGate'

export default class JwtService {
// ** jwtConfig <= Will be used by this service
@@ -126,8 +127,8 @@ export default class JwtService {
}

refreshToken() {
return axios.post(this.jwtConfig.refreshEndpoint, {
return beginRefresh(() => axios.post(this.jwtConfig.refreshEndpoint, {
refreshToken: this.getRefreshToken()
})
}))
}
}

+ 71
- 0
src/auth/refreshGate.js 查看文件

@@ -0,0 +1,71 @@
const LOCK_KEY = 'pnspsRefreshLock';
const LOCK_MS = 15000;

let inFlight = null;

function waitForStoredToken(previousRefreshToken) {
return new Promise((resolve, reject) => {
const started = Date.now();
const timer = setInterval(() => {
const refreshToken = localStorage.getItem('refreshToken');
const accessToken = localStorage.getItem('accessToken');
if (refreshToken && accessToken && refreshToken !== previousRefreshToken) {
clearInterval(timer);
resolve({
status: 200,
data: { accessToken, refreshToken }
});
return;
}
const lockGone = !localStorage.getItem(LOCK_KEY);
if ((lockGone && Date.now() - started > 500) || Date.now() - started > LOCK_MS) {
clearInterval(timer);
reject(new Error('refresh-lock-released'));
}
}, 200);
});
}

export function storeRefreshedTokens(accessToken, refreshToken) {
if (accessToken) {
localStorage.setItem('accessToken', accessToken);
localStorage.setItem('axiosToken', 'Bearer ' + accessToken);
}
if (refreshToken) {
localStorage.setItem('refreshToken', refreshToken);
}
}

/**
* One refresh at a time in this tab, and a short lock so a second tab waits
* for the new token instead of posting the same refresh token again.
*/
export function beginRefresh(run) {
if (inFlight) {
return inFlight;
}
const previousRefreshToken = localStorage.getItem('refreshToken');
inFlight = (async () => {
const lockedAt = Number(localStorage.getItem(LOCK_KEY) || 0);
if (lockedAt && Date.now() - lockedAt < LOCK_MS) {
try {
return await waitForStoredToken(previousRefreshToken);
} catch (e) {
// The other tab did not store a new token. Refresh from here.
}
}
localStorage.setItem(LOCK_KEY, String(Date.now()));
try {
const response = await run();
if (response?.status === 200 && response.data) {
storeRefreshedTokens(response.data.accessToken, response.data.refreshToken);
}
return response;
} finally {
localStorage.removeItem(LOCK_KEY);
}
})().finally(() => {
inFlight = null;
});
return inFlight;
}

+ 3
- 2
src/components/RefreshTokenProvider.js 查看文件

@@ -2,6 +2,7 @@ import { createContext, useEffect, useRef, useCallback } from 'react';
import { apiPath } from 'auth/utils';
import { REFRESH_TOKEN } from 'utils/ApiPathConst';
import axios from 'axios';
import { beginRefresh } from 'auth/refreshGate';
import {
isUserLoggedIn,
} from "utils/Utils";
@@ -16,10 +17,10 @@ const RefreshTokenProvider = ({ children }) => {
if (!isRefresh.current) {
const refreshToken = localStorage.getItem('refreshToken');
isRefresh.current = true;
axios
beginRefresh(() => axios
.post(`${apiPath}${REFRESH_TOKEN}`, {
refreshToken: refreshToken
})
}))
.then((response) => {
if (response.status === 200) {
const newAccessToken = response.data.accessToken;


Loading…
取消
儲存