Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

297 lignes
11 KiB

  1. // ** UseJWT import to get config
  2. import axios from "axios";
  3. import {isUserLoggedIn} from "../utils/Utils";
  4. import jwtApplicationConfig from "auth/jwtApplicationConfig";
  5. import jwt_decode from "jwt-decode";
  6. import {apiPath} from "./utils";
  7. //import axios from "axios";
  8. export const refreshIntervalName = 'refreshInterval'
  9. export const predictProductionQty = 'predictProductionQty'
  10. export const predictUsageCount = 'predictUsageCount'
  11. export const windowCount = 'windowCount'
  12. import {useNavigate} from "react-router-dom";
  13. import {useDispatch} from "react-redux";
  14. import { LOGOUT, REFRESH_TOKEN } from 'utils/ApiPathConst';
  15. import { getMessage } from 'utils/getI18nMessage';
  16. // Guard so we only register interceptors once (ThemeRoutes re-renders add duplicate handlers otherwise)
  17. let axiosInterceptorsSetup = false;
  18. // In-memory guard so only one 401/logout flow shows the alert (avoids race when multiple 401s or interceptors run)
  19. let expiredAlertShownInMemory = false;
  20. /** Login / public auth endpoints must not trigger token refresh or session-expiry reload. */
  21. const isPublicAuthRequest = (reqUrl) =>
  22. reqUrl.includes('/login') || reqUrl.includes('/refresh-token') || reqUrl.includes('/logout');
  23. /** Clear stale session-expiry flag so a new login attempt can show its own error dialog. */
  24. export const clearExpiredSessionAlert = () => {
  25. localStorage.removeItem('expiredAlertShown');
  26. expiredAlertShownInMemory = false;
  27. };
  28. // ** Handle User Login
  29. export const handleLogin = data => {
  30. return dispatch => {
  31. dispatch({
  32. type: 'LOGIN',
  33. data,
  34. jwtApplicationConfig,
  35. accessToken: data['accessToken'],
  36. refreshToken: data['refreshToken']
  37. })
  38. // console.log(data)
  39. // ** Add to user, accessToken & refreshToken to localStorage
  40. localStorage.setItem('userData', JSON.stringify(data))
  41. localStorage.setItem('accessToken', data.accessToken)
  42. localStorage.setItem('refreshToken', data.refreshToken)
  43. localStorage.setItem('axiosToken', "Bearer " + data.accessToken)
  44. localStorage.setItem('searchCriteria',"")
  45. //localStorage.setItem(config.storageUserRoleKeyName, JSON.stringify(data.role).slice(1).slice(0, -1))
  46. localStorage.setItem(refreshIntervalName, "60")
  47. // for demo only
  48. localStorage.setItem(windowCount, '0')
  49. localStorage.setItem(predictProductionQty, '0')
  50. localStorage.setItem(predictUsageCount, '0')
  51. localStorage.removeItem('expiredAlertShown')
  52. expiredAlertShownInMemory = false
  53. }
  54. }
  55. export const isLocalTokenValid = () => {
  56. axios.get(`${apiPath}/test`)
  57. .then((response) => {
  58. if(response.status === 200){
  59. return true;
  60. }
  61. else{
  62. return false;
  63. }
  64. })
  65. .catch(error => {
  66. console.log(error);
  67. return false;
  68. });
  69. return false;
  70. }
  71. export const isTokenValid = () =>{
  72. if(localStorage.getItem('accessToken') !== null && localStorage.getItem('accessToken') !== 'null'){
  73. let isExpired = false;
  74. const token = localStorage.getItem('accessToken');
  75. let decodedToken=jwt_decode(token);
  76. let dateNow = new Date();
  77. if(decodedToken.exp < dateNow.getTime())
  78. isExpired = true;
  79. return isExpired;
  80. }
  81. else{
  82. return false;
  83. }
  84. }
  85. // ** Handle User Logout
  86. export const handleLogoutFunction = () => {
  87. return dispatch => {
  88. const refreshToken = localStorage.getItem('refreshToken')
  89. if (refreshToken) {
  90. axios.post(`${apiPath}${LOGOUT}`, { refreshToken }).catch(() => {})
  91. }
  92. dispatch({
  93. type: 'LOGOUT',
  94. accessToken: null,
  95. refreshToken: null
  96. }
  97. )
  98. // console.log("logout");
  99. // ** Remove user, accessToken & refreshToken from localStorage
  100. localStorage.removeItem('userData')
  101. localStorage.removeItem('accessToken')
  102. localStorage.removeItem('refreshToken')
  103. localStorage.removeItem('webtoken')
  104. localStorage.removeItem('transactionid')
  105. localStorage.removeItem('searchCriteria')
  106. //localStorage.removeItem(config.storageUserRoleKeyName)
  107. // Do not clear expiredAlertShown / expiredAlertShownInMemory here: logout runs right after
  108. // the token-expired alert, and parallel 401s would each show another popup if we reset.
  109. // Reset those only on successful login (handleLogin).
  110. localStorage.removeItem(refreshIntervalName)
  111. localStorage.removeItem(windowCount)
  112. localStorage.removeItem(predictProductionQty)
  113. localStorage.removeItem(predictUsageCount)
  114. // setTimeout(()=> localStorage.removeItem("expiredAlertShown"), 5000)
  115. }
  116. }
  117. // ** Handle axios token
  118. export const SetupAxiosInterceptors = () => {
  119. const navigate = useNavigate()
  120. const dispatch = useDispatch();
  121. //const updateLastRequestTime = useContext(TimerContext);
  122. let isRefreshToken= false;
  123. // Avoid stacking interceptors on every ThemeRoutes re-render (would cause multiple alerts on 401)
  124. if (axiosInterceptorsSetup) {
  125. return;
  126. }
  127. axiosInterceptorsSetup = true;
  128. axios.interceptors.request.use(
  129. config => {
  130. // ** Get token from localStorage
  131. const accessToken = localStorage.getItem("accessToken")
  132. // ** If token is present add it to request's Authorization Header
  133. if (isUserLoggedIn()) {
  134. config.headers.Authorization = `${jwtApplicationConfig.tokenType} ${accessToken}`
  135. }
  136. config.headers['X-Authorization'] = process.env.REACT_APP_API_KEY
  137. return config
  138. },
  139. error => {
  140. Promise.reject(error)
  141. }
  142. )
  143. axios.interceptors.response.use(
  144. response => {
  145. //updateLastRequestTime(Date.now());
  146. return response;
  147. },
  148. async (error) => {
  149. // const { config, response: { status } } = error
  150. const status = error.response?.status
  151. const reqUrl = error.config?.url || ''
  152. // Let login forms handle their own errors (wrong password, locked account, etc.)
  153. if (isPublicAuthRequest(reqUrl)) {
  154. return Promise.reject(error)
  155. }
  156. // iAM Smart registration: HKID already linked — caller must show /iamsmart/pleaseLogin (not refresh/logout)
  157. if (
  158. status === 401 &&
  159. reqUrl.includes('/smart/getProfile') &&
  160. error.response?.data?.exception === 'msg: account created'
  161. ) {
  162. return Promise.reject(error)
  163. }
  164. if (
  165. status === 401 &&
  166. !isPublicAuthRequest(reqUrl) &&
  167. error.config?.url !== apiPath + REFRESH_TOKEN
  168. ) {
  169. // Make a request to refresh the access token
  170. const refreshToken = localStorage.getItem('refreshToken');
  171. if (isRefreshToken) {
  172. return Promise.reject(error);
  173. }
  174. isRefreshToken = true;
  175. return axios
  176. .post(`${apiPath}${REFRESH_TOKEN}`, {
  177. refreshToken: refreshToken // Replace with your refresh token
  178. })
  179. .then((response) => {
  180. if (response.status === 200) {
  181. const newAccessToken = response.data.accessToken;
  182. const newRefreshToken = response.data.refreshToken;
  183. localStorage.setItem('accessToken', newAccessToken);
  184. localStorage.setItem('refreshToken', newRefreshToken);
  185. isRefreshToken = false;
  186. window.location.reload();
  187. }
  188. })
  189. .catch((refreshError) => {
  190. isRefreshToken = false;
  191. if (!expiredAlertShownInMemory && localStorage.getItem("expiredAlertShown") === null) {
  192. expiredAlertShownInMemory = true;
  193. localStorage.setItem("expiredAlertShown", "true");
  194. alert(getMessage("autoLogout"));
  195. }
  196. dispatch(handleLogoutFunction());
  197. navigate('/login');
  198. window.location.reload();
  199. throw refreshError;
  200. });
  201. } else {
  202. if (error.response && error.response.status === 401) {
  203. if (!expiredAlertShownInMemory && localStorage.getItem("expiredAlertShown") === null) {
  204. expiredAlertShownInMemory = true;
  205. localStorage.setItem("expiredAlertShown", "true");
  206. alert(getMessage("autoLogout"));
  207. }
  208. }
  209. // ** if (status === 401) {
  210. // if (response.status === 401) {
  211. // if (localStorage.getItem("expiredAlertShown") === null) {
  212. // localStorage.setItem("expiredAlertShown", true)
  213. // alert("登入驗證已過期,請重新登入。")
  214. // }
  215. // }
  216. // if (response && response.status === 401) {
  217. // if (localStorage.getItem("expiredAlertShown") === null) {
  218. // localStorage.setItem("expiredAlertShown", true)
  219. // alert("登入驗證已過期,請重新登入。")
  220. // }
  221. // }
  222. if (localStorage.getItem("expiredAlertShown") && !isPublicAuthRequest(reqUrl)) {
  223. await dispatch(handleLogoutFunction());
  224. await navigate('/login');
  225. await window.location.reload();
  226. }
  227. if (error.response?.status === 500){
  228. //setIsUploading(false);
  229. }
  230. // console.log(error)
  231. }
  232. return Promise.reject(error)
  233. }
  234. )
  235. }
  236. export const handleRefreshTokenFunction = () => {
  237. // const token = localStorage.getItem('accessToken');
  238. let isRefresh = false;
  239. if (!isRefresh) {
  240. const refreshToken = localStorage.getItem('refreshToken');
  241. isRefresh = true;
  242. axios.post(`${apiPath}${REFRESH_TOKEN}`, {
  243. refreshToken: refreshToken
  244. }).then((response) => {
  245. if (response.status === 200) {
  246. const newAccessToken = response.data.accessToken;
  247. const newRefreshToken = response.data.refreshToken;
  248. localStorage.setItem('accessToken', newAccessToken);
  249. localStorage.setItem('refreshToken', newRefreshToken);
  250. // token = newAccessToken;
  251. isRefresh = false;
  252. } else {
  253. // token = null;
  254. isRefresh = false;
  255. }
  256. })
  257. .catch((refreshError) => {
  258. console.log('Failed to refresh token');
  259. if (refreshError != undefined){
  260. console.log(refreshError)
  261. }
  262. // token = null
  263. isRefresh = false;
  264. });
  265. }
  266. return isRefresh;
  267. }