Quellcode durchsuchen

fix: 小程序401跳转失败修复+token有效期延长至12个月

- handleUnauthorized 加防重入锁,避免多接口并发401时重复reLaunch
- verifyToken 改为三态返回(valid/invalid/unknown),网络异常不踢用户
- admin token 8h→12个月,miniapp token 7天→12个月

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
skyline vor 4 Tagen
Ursprung
Commit
30c1cff989

+ 2 - 2
haha-admin/src/main/resources/application.yml

@@ -71,8 +71,8 @@ server:
 sa-token:
   # token 名称(同时也是 cookie 名称)
   token-name: adminAccessToken
-  # token 有效期(单位:秒) - 8小时
-  timeout: 28800
+  # token 有效期(单位:秒) - 12个月
+  timeout: 31536000
   # token 临时有效期(单位:秒)
   active-timeout: -1
   # 是否允许同一账号多地同时登录

+ 2 - 2
haha-miniapp/src/main/resources/application.yml

@@ -112,8 +112,8 @@ haha:
 sa-token:
   # token 名称(同时也是 cookie 名称)
   token-name: accessToken
-  # token 有效期(单位:秒)- 7天
-  timeout: 604800
+  # token 有效期(单位:秒)- 12个月
+  timeout: 31536000
   # token 临时有效期(单位:秒)
   active-timeout: -1
   # 是否允许同一账号多地同时登录

+ 35 - 24
haha-mp/src/App.vue

@@ -45,19 +45,21 @@ const LOGIN_WHITE_LIST = [
 
 /**
  * 验证token是否有效
- * 调用后端用户信息接口校验token,最多等待3秒,
- * 超时则假定token有效(由后续API请求的401拦截兜底)
+ * @returns 'valid' | 'invalid' | 'unknown'
+ *   - valid: token确认有效
+ *   - invalid: 后端明确返回401,token已失效
+ *   - unknown: 网络异常/超时,无法确认(由后续API的401拦截兜底)
  */
-const verifyToken = (): Promise<boolean> => {
+const verifyToken = (): Promise<'valid' | 'invalid' | 'unknown'> => {
   return new Promise((resolve) => {
     const token = uni.getStorageSync('accessToken');
     if (!token) {
-      resolve(false);
+      resolve('invalid');
       return;
     }
 
     let settled = false;
-    const done = (result: boolean) => {
+    const done = (result: 'valid' | 'invalid' | 'unknown') => {
       if (!settled) {
         settled = true;
         resolve(result);
@@ -77,27 +79,32 @@ const verifyToken = (): Promise<boolean> => {
         if (res.statusCode === 200) {
           const data = res.data;
           if (data && (data.code === 200 || data.code === 0)) {
-            done(true);
+            done('valid');
           } else if (data && data.code === 401) {
             logger.log('[App] token无效:', data.message);
-            done(false);
+            done('invalid');
           } else {
             logger.warn('[App] 验证token返回异常状态:', data?.code, data?.message);
-            done(true);
+            done('unknown');
           }
+        } else if (res.statusCode === 401) {
+          logger.log('[App] HTTP 401, token无效');
+          done('invalid');
         } else {
-          logger.warn('[App] 验证token网络异常, statusCode:', res.statusCode);
-          done(true);
+          logger.warn('[App] 验证token HTTP状态异常:', res.statusCode);
+          done('unknown');
         }
       },
       fail: (err: any) => {
         logger.warn('[App] 验证token请求失败:', err.errMsg);
-        done(true);
+        done('unknown');
       }
     });
 
-    // 竞速兜底:最多等3秒,超时假定token有效
-    setTimeout(() => done(true), 3000);
+    setTimeout(() => {
+      logger.warn('[App] 验证token超时');
+      done('unknown');
+    }, 3000);
   });
 };
 
@@ -131,18 +138,22 @@ const checkLoginStatus = async (launchOptions?: any) => {
 
   // 有token,向后端验证是否有效
   logger.log('[App] token存在,验证token有效性...');
-  const isValid = await verifyToken();
-
-  if (!isValid && !isWhiteListed) {
-    // token无效且不在白名单 -> 触发全局未授权处理
-    logger.log('[App] token无效,触发全局未授权处理');
-    handleUnauthorized();
-  } else if (!isValid && isWhiteListed) {
-    // 白名单页面只清除数据不跳转(不触发全局未授权处理的重定向)
-    logger.log('[App] token无效,清除登录数据(当前在白名单页面)');
-    clearAuth();
-  } else {
+  const verifyResult = await verifyToken();
+
+  if (verifyResult === 'valid') {
     logger.log('[App] token有效');
+  } else if (verifyResult === 'invalid') {
+    // 后端明确返回401:token已失效,必须跳转登录
+    if (!isWhiteListed) {
+      logger.log('[App] token已失效,触发全局未授权处理');
+      handleUnauthorized();
+    } else {
+      logger.log('[App] token已失效,清除登录数据(当前在白名单页面)');
+      clearAuth();
+    }
+  } else {
+    // unknown:网络异常或超时,不踢用户,交给后续API的401拦截处理
+    logger.log('[App] token验证无法确认,保留token继续运行(由API请求401兜底)');
   }
 };
 </script>

+ 11 - 1
haha-mp/src/utils/auth.ts

@@ -102,12 +102,22 @@ export const checkAuth = (redirectUrl?: string): boolean => {
  * 全局401未授权处理
  * 清除所有登录信息并跳转到登录页
  * 任何接口遇到401时都应调用此函数
+ * 内置防重入保护:同一时间只执行一次跳转
  */
+let unauthorizing = false;
 export const handleUnauthorized = (): void => {
+  if (unauthorizing) {
+    logger.log('[Auth] 已在处理未授权跳转,跳过重复调用');
+    return;
+  }
+  unauthorizing = true;
   logger.log('[Auth] token无效或已过期,清除登录信息并跳转登录页');
   clearAuth();
   uni.reLaunch({
-    url: '/pages/login/login'
+    url: '/pages/login/login',
+    complete: () => {
+      unauthorizing = false;
+    }
   });
 };