Browse Source

Merge branch 'new_dev' of https://github.com/deepcloud2048/deep_voice into new_dev

newdev_shunjiawei
liwei1dao 1 year ago
parent
commit
ab359fd0ef
  1. 193
      lib/modules/login/controllers/appleLogin.dart
  2. 49
      lib/modules/login/controllers/login_controller.dart
  3. 2
      pubspec.yaml

193
lib/modules/login/controllers/appleLogin.dart

@ -1,12 +1,12 @@
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/foundation.dart';
import 'package:sign_in_with_apple/sign_in_with_apple.dart';
import 'package:crypto/crypto.dart';
import 'package:get/get.dart';
/// Apple登录控制器(纯sign_in_with_apple实现)
class Apple {
String? token = '';
String name = '';
@ -14,7 +14,12 @@ class Apple {
String pictureurl = '';
String id = '';
/// 生成随机nonce字符串
// 存储原始的Apple凭证信息
String? _identityToken;
String? _authorizationCode;
String? _userIdentifier;
/// 生成随机nonce字符串(用于安全验证)
String generateNonce([int length = 32]) {
const charset =
'0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._';
@ -30,7 +35,7 @@ class Apple {
return digest.toString();
}
/// Apple登录主方法
/// Apple登录主方法(纯sign_in_with_apple实现)
Future<bool> signInWithApple() async {
try {
// 检查Apple登录可用性
@ -41,11 +46,23 @@ class Apple {
return false;
}
UserCredential userCredential = await loginApple();
token = await userCredential.user?.getIdToken();
if (kDebugMode) {
print('开始执行Apple登录流程');
}
// 执行Apple登录
final appleCredential = await _getAppleCredential();
// 提取并存储用户信息
_extractUserInfo(appleCredential);
// 使用identityToken作为登录token
token = appleCredential.identityToken;
if (kDebugMode) {
print('Apple登录响应数据token: $token');
print('Apple登录成功');
print('Token: $token');
print('用户信息: name=$name, email=$email, id=$id');
}
return token != null && token!.isNotEmpty;
@ -57,83 +74,102 @@ class Apple {
}
}
/// 执行Apple登录流程
Future<UserCredential> loginApple() async {
// 生成nonce用于安全验证
/// 获取Apple登录凭证
Future<AuthorizationCredentialAppleID> _getAppleCredential() async {
// 生成nonce用于安全验证(遵循官方最佳实践)
final rawNonce = generateNonce();
final nonce = sha256ofString(rawNonce);
try {
// 请求Apple登录凭证
// 请求Apple登录凭证(与官方示例保持一致的参数结构)
final appleCredential = await SignInWithApple.getAppleIDCredential(
scopes: [
AppleIDAuthorizationScopes.email,
AppleIDAuthorizationScopes.fullName,
],
nonce: nonce,
// 可以添加state参数用于防CSRF攻击(可选)
state: 'voitrans-login-${DateTime.now().millisecondsSinceEpoch}',
);
// 提取用户信息
_extractUserInfo(appleCredential);
// 创建Firebase OAuth凭证
final oauthCredential = OAuthProvider("apple.com").credential(
idToken: appleCredential.identityToken,
rawNonce: rawNonce,
);
// 存储原始凭证信息(遵循官方示例的数据提取方式)
_identityToken = appleCredential.identityToken;
_authorizationCode = appleCredential.authorizationCode;
_userIdentifier = appleCredential.userIdentifier;
if (kDebugMode) {
print('Apple OAuth凭证创建成功');
print('用户信息: name=$name, email=$email, id=$id');
print('Apple凭证获取成功');
print('Identity Token长度: ${_identityToken?.length ?? 0}');
print('Authorization Code长度: ${_authorizationCode?.length ?? 0}');
print('User Identifier: $_userIdentifier');
print('State: ${appleCredential.state}');
// 调试输出用户信息(与官方示例类似)
if (appleCredential.givenName != null) {
print('Given Name: ${appleCredential.givenName}');
}
if (appleCredential.familyName != null) {
print('Family Name: ${appleCredential.familyName}');
}
if (appleCredential.email != null) {
print('Email: ${appleCredential.email}');
}
}
// 使用Firebase Auth进行登录
return await FirebaseAuth.instance.signInWithCredential(oauthCredential);
return appleCredential;
} catch (e) {
if (kDebugMode) {
print('Apple登录流程异常:$e');
print('获取Apple凭证异常:$e');
}
throw Exception('Apple登录失败: $e');
throw Exception('获取Apple凭证失败: $e');
}
}
/// 提取Apple返回的用户信息
/// 提取Apple返回的用户信息(遵循官方示例的处理方式)
void _extractUserInfo(AuthorizationCredentialAppleID credential) {
// 用户ID
// 用户ID(官方示例中的主要标识符)
id = credential.userIdentifier ?? '';
// 邮箱(可能为空,如果用户选择隐藏邮箱)
email = credential.email ?? '';
// 用户姓名(仅首次登录时提供)
if (credential.givenName != null || credential.familyName != null) {
final givenName = credential.givenName ?? '';
final familyName = credential.familyName ?? '';
name = '$givenName $familyName'.trim();
// 用户姓名处理(与官方示例保持一致的逻辑)
// 注意:姓名信息仅在首次登录时提供
final givenName = credential.givenName;
final familyName = credential.familyName;
if (givenName != null || familyName != null) {
// 按照官方示例的方式组合姓名
final firstName = givenName ?? '';
final lastName = familyName ?? '';
name = '$firstName $lastName'.trim();
} else {
// 如果没有姓名信息,保持空值(后续登录不会提供姓名)
name = '';
}
// Apple不提供头像,使用默认值
pictureurl = '';
if (kDebugMode) {
print('提取的用户信息:');
print('ID: $id');
print('Email: $email');
print('Name: $name');
print('=== 提取的用户信息 ===');
print('User Identifier: $id');
print('Email: ${email.isEmpty ? "未提供或隐藏" : email}');
print('Given Name: ${givenName ?? "未提供"}');
print('Family Name: ${familyName ?? "未提供"}');
print('Combined Name: ${name.isEmpty ? "未提供" : name}');
print('Picture URL: $pictureurl');
print('========================');
}
}
/// 退出Apple登录
Future<void> signOutApple() async {
try {
await FirebaseAuth.instance.signOut();
// 清空用户信息
token = '';
name = '';
email = '';
pictureurl = '';
id = '';
_clearUserInfo();
if (kDebugMode) {
print('Apple登录退出成功');
@ -145,14 +181,87 @@ class Apple {
}
}
/// 清空用户信息
void _clearUserInfo() {
token = '';
name = '';
email = '';
pictureurl = '';
id = '';
_identityToken = null;
_authorizationCode = null;
_userIdentifier = null;
}
/// 检查Apple登录环境
static Future<void> checkAppleSignInEnvironment() async {
if (kDebugMode) {
print('=== Apple登录环境检查 ===');
print('平台: ${GetPlatform.isIOS ? "iOS" : "非iOS"}');
print('Apple登录可用性: ${await SignInWithApple.isAvailable()}');
print('Firebase Auth实例: ${FirebaseAuth.instance.currentUser?.uid ?? "未登录"}');
// 检测设备地区
final locale = Get.deviceLocale;
final countryCode = locale?.countryCode?.toUpperCase();
print('设备地区: $countryCode');
print('认证方式: 纯Apple登录(无Firebase依赖)');
print('========================');
}
}
/// 获取认证方式名称
String getAuthMethodName() {
return 'Apple Sign-In';
}
/// 获取详细的凭证信息(用于调试)
Map<String, String?> getCredentialInfo() {
return {
'identityToken': _identityToken,
'authorizationCode': _authorizationCode,
'userIdentifier': _userIdentifier,
'name': name,
'email': email,
'id': id,
};
}
/// 获取用于后端验证的数据(遵循官方示例的后端集成方式)
///
/// [deviceId] 设备ID
/// 返回格式化的登录数据,包含Apple凭证信息
Map<String, dynamic> getLoginData(String deviceId) {
return {
// 现有系统兼容的字段
"mail": email,
"phone": "",
"stype": 5, // Apple登录类型
"vcode": "",
"ttoken": token ?? '', // 主要使用identityToken
"phonemodel": "",
"phonemac": deviceId,
"name": name,
"avatar": pictureurl,
"auth_method": "apple_signin", // 标识使用纯Apple登录
// Apple特有的凭证信息(遵循官方示例)
"apple_credentials": {
"identity_token": _identityToken,
"authorization_code": _authorizationCode,
"user_identifier": _userIdentifier,
"email": email,
"name": name,
}
};
}
/// 获取原始Apple凭证信息(用于高级验证)
Map<String, String?> getAppleCredentials() {
return {
'identityToken': _identityToken,
'authorizationCode': _authorizationCode,
'userIdentifier': _userIdentifier,
};
}
}

49
lib/modules/login/controllers/login_controller.dart

@ -2,6 +2,7 @@ import '../../../data/models/appconfig.dart';
import '../../../data/models/appconfig_model.dart';
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:logger/web.dart';
import '../../../routes/app_routes.dart';
import 'dart:convert';
@ -881,28 +882,39 @@ class LoginController extends GetxController {
}
case 5: //Apple登录
{
Logger().d("数据获取Apple");
Logger().d("开始Apple登录流程");
final apple = Apple();
// 先检查环境(调试用)
if (kDebugMode) {
await Apple.checkAppleSignInEnvironment();
}
bool authResult = await apple.signInWithApple();
if (authResult) {
Logger().d("数据获取_Apple.token${apple.token}");
Logger().d("数据获取_Apple.email${apple.email}");
Logger().d("数据获取_Apple.name${apple.name}");
Logger().d("数据获取_Apple.id${apple.id}");
// 验证成功,跳转到配对页面
requestLogin({
"mail": apple.email,
"phone": "",
"stype": loginType,
"vcode": "",
"ttoken": apple.token,
"phonemodel": "",
"phonemac": _deviceId,
"name": apple.name,
"avatar": apple.pictureurl,
});
Logger().d("Apple登录成功");
Logger().d("认证方式: ${apple.getAuthMethodName()}");
Logger().d("Token: ${apple.token}");
Logger().d("Email: ${apple.email}");
Logger().d("Name: ${apple.name}");
Logger().d("ID: ${apple.id}");
// 获取登录数据并发送到后端
final loginData = apple.getLoginData(_deviceId);
Logger().d("发送登录数据: $loginData");
// 直接调用现有的requestLogin方法
requestLogin(loginData);
} else {
Logger().e("Apple登录失败");
Get.snackbar(
'error'.tr,
'Apple登录失败,请重试',
snackPosition: SnackPosition.TOP,
backgroundColor: Colors.red.withValues(alpha: 0.1),
colorText: Colors.red,
);
}
break;
}
@ -1029,4 +1041,5 @@ class LoginController extends GetxController {
return false;
}
}
}

2
pubspec.yaml

@ -65,7 +65,7 @@ dependencies:
firebase_auth: ^5.5.1
google_sign_in: ^6.2.2
flutter_facebook_auth: ^7.1.1
sign_in_with_apple: ^6.1.2
sign_in_with_apple: ^7.0.1
flutter_image_compress: ^2.4.0
common_utils: ^2.1.0
image_gallery_saver_plus: ^4.0.1

Loading…
Cancel
Save