fix:对齐金值,主要注销,一键登录等方面修改
This commit is contained in:
1 parent
e29ed0a2c8
commit
6997a65c96
37 files changed
+3442
-514
No files matched your search
@@ -1,14 +1,10 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
import '../../../common/network/dio_provider.dart';
|
||||
import '../../../models/pb/jinzhi/v1/account.pb.dart' as pb;
|
||||
import 'auth_models.dart';
|
||||
|
||||
/// 金值账号服务的 protobuf HTTP 契约。
|
||||
///
|
||||
/// 这个轻量编解码只覆盖短信登录需要的字段,避免把整套历史生成模型带入
|
||||
/// 当前重建中的应用;字段号与金值 `account.proto` 保持一致。
|
||||
/// 金值账户的 protobuf-over-HTTP 客户端。
|
||||
class AuthApi {
|
||||
const AuthApi(this._dio);
|
||||
|
||||
@@ -17,124 +13,82 @@ class AuthApi {
|
||||
Future<int> sendSmsCode(String phone) async {
|
||||
final response = await _dio.post<List<int>>(
|
||||
'/api/v1/auth/sms/send',
|
||||
// Dio may JSON-encode a List<int> as `[10,11,...]`. The API expects
|
||||
// the raw protobuf bytes, so preserve the binary payload explicitly.
|
||||
data: Uint8List.fromList(_ProtoWriter.stringField(1, phone)),
|
||||
data: pb.SendSmsCodeRequest(phone: phone).writeToBuffer(),
|
||||
options: protobufOptions(),
|
||||
);
|
||||
return _ProtoMessage(response.data ?? const <int>[]).integer(1);
|
||||
return pb.SendSmsCodeReply.fromBuffer(
|
||||
response.data ?? const <int>[],
|
||||
).expiresIn;
|
||||
}
|
||||
|
||||
Future<AuthLoginResult> verifySmsCode(String phone, String code) async {
|
||||
final response = await _dio.post<List<int>>(
|
||||
'/api/v1/auth/sms/verify',
|
||||
data: Uint8List.fromList([
|
||||
..._ProtoWriter.stringField(1, phone),
|
||||
..._ProtoWriter.stringField(2, code),
|
||||
]),
|
||||
data: pb.VerifySmsCodeRequest(phone: phone, code: code).writeToBuffer(),
|
||||
options: protobufOptions(),
|
||||
);
|
||||
final reply = _ProtoMessage(response.data ?? const <int>[]);
|
||||
final accessToken = reply.string(1).trim();
|
||||
if (accessToken.isEmpty) {
|
||||
throw const FormatException('登录响应缺少 access_token');
|
||||
return AuthLoginResult.fromProto(
|
||||
pb.VerifySmsCodeReply.fromBuffer(response.data ?? const <int>[]),
|
||||
);
|
||||
}
|
||||
|
||||
Future<AuthLoginResult> verifyOneKeyLogin(String loginToken) async {
|
||||
final response = await _dio.post<List<int>>(
|
||||
'/api/v1/auth/onekey/verify',
|
||||
data: pb.VerifyOneKeyLoginRequest(loginToken: loginToken).writeToBuffer(),
|
||||
options: protobufOptions(),
|
||||
);
|
||||
return AuthLoginResult.fromProto(
|
||||
pb.VerifySmsCodeReply.fromBuffer(response.data ?? const <int>[]),
|
||||
);
|
||||
}
|
||||
|
||||
Future<JinzhiUser> getProfile() async {
|
||||
final response = await _dio.get<List<int>>(
|
||||
'/api/v1/me',
|
||||
options: protobufOptions(),
|
||||
);
|
||||
final reply = pb.ProfileReply.fromBuffer(response.data ?? const <int>[]);
|
||||
if (!reply.hasUser()) {
|
||||
throw const FormatException('账号资料响应缺少 user');
|
||||
}
|
||||
final user = _ProtoMessage(reply.bytes(3));
|
||||
return AuthLoginResult(
|
||||
accessToken: accessToken,
|
||||
phone: user.string(2).trim().isEmpty ? phone : user.string(2).trim(),
|
||||
return _userFromProto(reply.user);
|
||||
}
|
||||
|
||||
Future<void> deleteAccount(String smsCode) async {
|
||||
await _dio.delete<List<int>>(
|
||||
'/api/v1/me',
|
||||
data: pb.DeleteAccountRequest(smsCode: smsCode).writeToBuffer(),
|
||||
options: protobufOptions(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AuthLoginResult {
|
||||
const AuthLoginResult({required this.accessToken, required this.phone});
|
||||
const AuthLoginResult({
|
||||
required this.accessToken,
|
||||
required this.expiresIn,
|
||||
required this.user,
|
||||
});
|
||||
|
||||
final String accessToken;
|
||||
final String phone;
|
||||
}
|
||||
final int expiresIn;
|
||||
final JinzhiUser user;
|
||||
|
||||
class _ProtoWriter {
|
||||
static List<int> stringField(int field, String value) => [
|
||||
..._varint(field << 3 | 2),
|
||||
..._varint(utf8.encode(value).length),
|
||||
...utf8.encode(value),
|
||||
];
|
||||
|
||||
static List<int> _varint(int value) {
|
||||
final bytes = <int>[];
|
||||
var remaining = value;
|
||||
while (remaining > 0x7f) {
|
||||
bytes.add(remaining & 0x7f | 0x80);
|
||||
remaining >>= 7;
|
||||
factory AuthLoginResult.fromProto(pb.VerifySmsCodeReply reply) {
|
||||
if (reply.accessToken.trim().isEmpty || !reply.hasUser()) {
|
||||
throw const FormatException('登录响应缺少 access_token 或 user');
|
||||
}
|
||||
bytes.add(remaining);
|
||||
return bytes;
|
||||
return AuthLoginResult(
|
||||
accessToken: reply.accessToken.trim(),
|
||||
expiresIn: reply.expiresIn,
|
||||
user: _userFromProto(reply.user),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ProtoMessage {
|
||||
_ProtoMessage(List<int> bytes) : _fields = _parse(bytes);
|
||||
|
||||
final Map<int, Object> _fields;
|
||||
|
||||
int integer(int field) => _fields[field] is int ? _fields[field]! as int : 0;
|
||||
|
||||
String string(int field) => _fields[field] is List<int>
|
||||
? utf8.decode(_fields[field]! as List<int>, allowMalformed: true)
|
||||
: '';
|
||||
|
||||
List<int> bytes(int field) => _fields[field] is List<int>
|
||||
? _fields[field]! as List<int>
|
||||
: const <int>[];
|
||||
|
||||
static Map<int, Object> _parse(List<int> bytes) {
|
||||
final fields = <int, Object>{};
|
||||
var cursor = 0;
|
||||
while (cursor < bytes.length) {
|
||||
final tag = _readVarint(bytes, cursor);
|
||||
if (tag == null) break;
|
||||
cursor = tag.next;
|
||||
final field = tag.value >> 3;
|
||||
switch (tag.value & 7) {
|
||||
case 0:
|
||||
final value = _readVarint(bytes, cursor);
|
||||
if (value == null) return fields;
|
||||
fields[field] = value.value;
|
||||
cursor = value.next;
|
||||
case 2:
|
||||
final length = _readVarint(bytes, cursor);
|
||||
if (length == null || length.next + length.value > bytes.length) {
|
||||
return fields;
|
||||
}
|
||||
fields[field] = bytes.sublist(
|
||||
length.next,
|
||||
length.next + length.value,
|
||||
);
|
||||
cursor = length.next + length.value;
|
||||
default:
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
static _ProtoValue? _readVarint(List<int> bytes, int cursor) {
|
||||
var value = 0;
|
||||
var shift = 0;
|
||||
while (cursor < bytes.length && shift <= 63) {
|
||||
final byte = bytes[cursor++];
|
||||
value |= (byte & 0x7f) << shift;
|
||||
if (byte & 0x80 == 0) return _ProtoValue(value, cursor);
|
||||
shift += 7;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class _ProtoValue {
|
||||
const _ProtoValue(this.value, this.next);
|
||||
|
||||
final int value;
|
||||
final int next;
|
||||
}
|
||||
JinzhiUser _userFromProto(pb.UserInfo user) => JinzhiUser(
|
||||
id: user.id.trim(),
|
||||
phone: user.phone.trim(),
|
||||
createdAt: user.createdAt.trim(),
|
||||
);
|
||||
Reference in new issue
Block a user