fix:商城登录互通问题

This commit is contained in:
jingyun committed 2026-09-08 13:46:45 +08:00
1 parent 7b1852d9a6
commit 1f9a8b67a2
4 files changed
+119 -9

No files matched your search

+11 -3
View File
@@ -47,11 +47,19 @@ class LoginPage extends HookConsumerWidget {
Future<void> returnAfterLogin() async { Future<void> returnAfterLogin() async {
final target = next?.trim(); final target = next?.trim();
final router = GoRouter.of(context); final router = GoRouter.of(context);
if (target == null || target.isEmpty) { if (target != null && target.isNotEmpty) {
router.go(AppRoutes.profile); router.go(target);
return; return;
} }
router.go(target); // The mall opens this page with no `next`. Pop back to its resident
// WebView so the auth-state listener can deliver `enterWebMall` after
// the app-mall token has been issued. Replacing the route here disposes
// that WebView before the asynchronous hand-off can finish.
if (context.canPop()) {
context.pop();
} else {
router.go(AppRoutes.profile);
}
} }
void startCountdown() { void startCountdown() {
+15 -5
View File
@@ -1,3 +1,5 @@
import 'dart:typed_data';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
@@ -25,17 +27,25 @@ class MallAuthApi {
Future<AppMallAuthToken> issueAppMallAuthToken() async { Future<AppMallAuthToken> issueAppMallAuthToken() async {
final response = await _dio.post<List<int>>( final response = await _dio.post<List<int>>(
'/api/v1/auth/mall/app-token', '/api/v1/auth/mall/app-token',
data: const <int>[], // Dio serializes a List<int> as the UTF-8 text "[]". This endpoint
// expects an empty protobuf message, whose wire representation is zero
// bytes; Uint8List keeps the request body binary and untransformed.
data: Uint8List(0),
options: protobufOptions(), options: protobufOptions(),
); );
final reply = ProtoMessage(response.data ?? const <int>[]); final reply = ProtoMessage(response.data ?? const <int>[]);
final token = reply.string(1).trim(); final token = reply.string(1).trim();
if (token.isEmpty) throw const FormatException('Missing mall auth token'); final expiresIn = reply.integer(2);
final sourceApp = reply.string(3).trim();
final scene = reply.string(4).trim();
if (token.isEmpty || expiresIn <= 0 || sourceApp.isEmpty || scene.isEmpty) {
throw const FormatException('Incomplete mall auth token response');
}
return AppMallAuthToken( return AppMallAuthToken(
authToken: token, authToken: token,
expiresIn: reply.integer(2), expiresIn: expiresIn,
sourceApp: reply.string(3), sourceApp: sourceApp,
scene: reply.string(4), scene: scene,
); );
} }
} }
+1 -1
View File
@@ -2,7 +2,7 @@ name: jinzhi_flutter_app
description: "金值 - 贵金属资产管家" description: "金值 - 贵金属资产管家"
publish_to: 'none' publish_to: 'none'
version: 1.0.0+1 version: 1.3.0+1
environment: environment:
sdk: ^3.9.2 sdk: ^3.9.2
@@ -0,0 +1,92 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:dio/dio.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:jinzhi_flutter_app/features/mall/data/mall_auth_api.dart';
void main() {
test('sends an empty protobuf body when issuing a mall auth token', () async {
Object? requestData;
String? contentType;
final dio = Dio()
..interceptors.add(
InterceptorsWrapper(
onRequest: (options, handler) {
requestData = options.data;
contentType = options.contentType;
handler.resolve(
Response<List<int>>(
requestOptions: options,
statusCode: 200,
data: _validResponse(),
),
);
},
),
);
final token = await MallAuthApi(dio).issueAppMallAuthToken();
expect(requestData, isA<Uint8List>());
expect(requestData, isEmpty);
expect(contentType, 'application/x-protobuf');
expect(token.authToken, 'mall-token');
expect(token.expiresIn, 300);
expect(token.sourceApp, 'jinzhi');
expect(token.scene, 'web_mall');
});
test('rejects an incomplete mall auth token response', () async {
final dio = Dio()
..interceptors.add(
InterceptorsWrapper(
onRequest: (options, handler) {
handler.resolve(
Response<List<int>>(
requestOptions: options,
statusCode: 200,
data: _stringField(1, 'mall-token'),
),
);
},
),
);
await expectLater(
MallAuthApi(dio).issueAppMallAuthToken(),
throwsFormatException,
);
});
}
List<int> _validResponse() => <int>[
..._stringField(1, 'mall-token'),
..._integerField(2, 300),
..._stringField(3, 'jinzhi'),
..._stringField(4, 'web_mall'),
];
List<int> _stringField(int field, String value) {
final bytes = utf8.encode(value);
return <int>[
..._varint((field << 3) | 2),
..._varint(bytes.length),
...bytes,
];
}
List<int> _integerField(int field, int value) => <int>[
..._varint(field << 3),
..._varint(value),
];
List<int> _varint(int value) {
final bytes = <int>[];
while (value > 0x7f) {
bytes.add((value & 0x7f) | 0x80);
value >>= 7;
}
bytes.add(value);
return bytes;
}