Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

145 рядки
5.4 KiB

  1. import axios from 'axios'
  2. import jwtDefaultConfig from './jwtDefaultConfig'
  3. import { isAccessTokenUsable, forceLocalLogoutRedirect } from '../tokenSession'
  4. export default class JwtService {
  5. // ** jwtConfig <= Will be used by this service
  6. jwtConfig = {...jwtDefaultConfig}
  7. // ** For Refreshing Token
  8. isAlreadyFetchingAccessToken = false
  9. // ** For Refreshing Token
  10. subscribers = []
  11. constructor(jwtOverrideConfig) {
  12. this.jwtConfig = {...this.jwtConfig, ...jwtOverrideConfig}
  13. // ** Request Interceptor
  14. axios.interceptors.request.use(
  15. config => {
  16. // ** Get token from localStorage
  17. const accessToken = this.getToken()
  18. // ** If token is present add it to request's Authorization Header
  19. if (accessToken) {
  20. // ** eslint-disable-next-line no-param-reassign
  21. config.headers.Authorization = `${this.jwtConfig.tokenType} ${accessToken}`
  22. }
  23. config.headers['X-Authorization'] = process.env.REACT_APP_API_KEY
  24. return config
  25. },
  26. error => Promise.reject(error)
  27. )
  28. // ** Add request/response interceptor
  29. axios.interceptors.response.use(
  30. response => response,
  31. error => {
  32. // ** const { config, response: { status } } = error
  33. const {config, response} = error
  34. const originalRequest = config
  35. const reqUrl = config?.url || ''
  36. // ** if (status === 401) {
  37. if (response && response.status === 401) {
  38. const isPublicAuthRequest =
  39. reqUrl.includes('/login') ||
  40. reqUrl.includes('/refresh-token')
  41. if (isPublicAuthRequest) {
  42. return Promise.reject(error)
  43. }
  44. if (!this.isAlreadyFetchingAccessToken) {
  45. this.isAlreadyFetchingAccessToken = true
  46. this.refreshToken()
  47. .then(r => {
  48. this.isAlreadyFetchingAccessToken = false
  49. const newAccessToken = r.data.accessToken
  50. const newRefreshToken = r.data.refreshToken
  51. if (
  52. isAccessTokenUsable(newAccessToken) &&
  53. typeof newRefreshToken === 'string' &&
  54. newRefreshToken
  55. ) {
  56. // ** Update accessToken in localStorage
  57. this.setToken(newAccessToken)
  58. this.setRefreshToken(newRefreshToken)
  59. this.onAccessTokenFetched(newAccessToken)
  60. } else {
  61. this.onAccessTokenFetchFailed(new Error('Invalid access token from refresh'))
  62. forceLocalLogoutRedirect()
  63. }
  64. })
  65. .catch(refreshError => {
  66. this.isAlreadyFetchingAccessToken = false
  67. this.onAccessTokenFetchFailed(refreshError)
  68. })
  69. }
  70. const retryOriginalRequest = new Promise((resolve, reject) => {
  71. this.addSubscriber(
  72. accessToken => {
  73. // ** Make sure to assign accessToken according to your response.
  74. // ** Check: https://pixinvent.ticksy.com/ticket/2413870
  75. // ** Change Authorization header
  76. originalRequest.headers.Authorization = `${this.jwtConfig.tokenType} ${accessToken}`
  77. resolve(axios(originalRequest))
  78. },
  79. reject
  80. )
  81. })
  82. return retryOriginalRequest
  83. }
  84. return Promise.reject(error)
  85. }
  86. )
  87. }
  88. onAccessTokenFetched(accessToken) {
  89. this.subscribers.forEach(({ onSuccess }) => onSuccess(accessToken))
  90. this.subscribers = []
  91. }
  92. onAccessTokenFetchFailed(refreshError) {
  93. this.subscribers.forEach(({ onFailure }) => onFailure(refreshError))
  94. this.subscribers = []
  95. }
  96. addSubscriber(onSuccess, onFailure) {
  97. this.subscribers.push({ onSuccess, onFailure })
  98. }
  99. getToken() {
  100. return localStorage.getItem(this.jwtConfig.storageTokenKeyName)
  101. }
  102. getRefreshToken() {
  103. return localStorage.getItem(this.jwtConfig.storageRefreshTokenKeyName)
  104. }
  105. setToken(value) {
  106. localStorage.setItem(this.jwtConfig.storageTokenKeyName, value)
  107. }
  108. setRefreshToken(value) {
  109. localStorage.setItem(this.jwtConfig.storageRefreshTokenKeyName, value)
  110. }
  111. login(...args) {
  112. return axios.post(this.jwtConfig.loginEndpoint, ...args)
  113. }
  114. register(...args) {
  115. return axios.post(this.jwtConfig.registerEndpoint, ...args)
  116. }
  117. refreshToken() {
  118. return axios.post(this.jwtConfig.refreshEndpoint, {
  119. refreshToken: this.getRefreshToken()
  120. })
  121. }
  122. }