Token架构优化:防重放攻击清除token、防重复forceLogout、refreshToken空值防御

This commit is contained in:
2026-04-16 13:12:35 +08:00
parent 8d0ce203ef
commit 5904d209fd
7 changed files with 55 additions and 21 deletions

View File

@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"e4b8dca3f1b4ede4c30371002441c88c12187e
_flutter.loader.load({
serviceWorkerSettings: {
serviceWorkerVersion: "112731293" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
serviceWorkerVersion: "3241221564" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
}
});

View File

@@ -29185,9 +29185,11 @@ _.c=c
_.$ti=d},
b47(a){return B.b.hY(B.a2v,new A.aS1(a))},
aS1:function aS1(a){this.a=a},
DU:function DU(a){this.a=$
this.b=a
this.c=null},
DU:function DU(a){var _=this
_.a=$
_.b=a
_.c=null
_.d=!1},
aji:function aji(){},
re:function re(a,b,c,d){var _=this
_.d=a
@@ -102824,11 +102826,13 @@ A.cR().$1("ResponseData: "+A.l(r?q:s.a))
A.cR().$1("====================")
if((r?q:s.c)===401)return new A.cg(!1,"\u767b\u9304\u5df2\u904e\u671f\uff0c\u8acb\u91cd\u65b0\u767b\u9304",q,b.i("cg<0>"))
return new A.cg(!1,this.ajp(a),q,b.i("cg<0>"))},
Eu(){var s,r,q
Eu(){var s,r,q,p=this
if(p.d)return
p.d=!0
A.yj()
s=this.c
s=p.c
if(s!=null)s.$0()
r=$.a5.aq$.x.h(0,this.b)
r=$.a5.aq$.x.h(0,p.b)
if(r!=null){s=A.c_(r,!1)
q=s.xc("/login",null,t.X)
q.toString
@@ -102905,7 +102909,8 @@ g=t.z
e=m.d
s=j!=null?15:17
break
case 15:d=a.b
case 15:e.d=!1
d=a.b
d===$&&A.a()
d.m(0,"Authorization","Bearer "+j)
e=e.a

View File

@@ -33,7 +33,7 @@ class ApiEndpoints {
/// 退出登錄
static const String logout = '/api/user/logout';
/// 刷新 Token(後端尚未實現,預留接口)
/// 刷新 Token
static const String tokenRefresh = '/api/auth/refresh';
// ==================== 行情模塊 ====================

View File

@@ -35,6 +35,9 @@ class DioClient {
/// 未授權回調token 徹底過期時觸發 AuthProvider.forceLogout
VoidCallback? onForceLogout;
/// 防止重複 forceLogout
bool hasForceLoggedOut = false;
DioClient({this.navigatorKey}) {
_dio = _createDio();
_setupInterceptors();
@@ -133,8 +136,10 @@ class DioClient {
return ApiResponse.fail(message);
}
/// 徹底失效時清除數據並跳轉登錄頁
/// 徹底失效時清除數據並跳轉登錄頁(防重複調用)
void forceLogout() {
if (hasForceLoggedOut) return;
hasForceLoggedOut = true;
LocalStorage.clearUserData();
onForceLogout?.call();
final context = navigatorKey?.currentContext;
@@ -253,6 +258,8 @@ class _TokenRefreshInterceptor extends QueuedInterceptor {
try {
final newToken = await _refreshToken();
if (newToken != null) {
// 刷新成功,重置 forceLogout 標記(用戶重新激活)
_client.hasForceLoggedOut = false;
// 刷新成功,更新 header 並重試原始請求
requestOptions.headers['Authorization'] = 'Bearer $newToken';
final retryResponse = await _client._dio.fetch(requestOptions);